# Proposal: LiteralEnum — runtime literals with static exhaustiveness

**URL:** <https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000>\
**Category:** Typing\
**Tags:** typing\
**Created:** [February 4, 2026, 9:40am UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000 "2026-02-04T09:40:15Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![modularizer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/modularizer/32/34039_2.png) [@modularizer](https://discuss.python.org/u/modularizer)\
**Post date:** [February 4, 2026, 9:40am UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/1 "2026-02-04T09:40:15Z")

</div>

Hello typing community​👋,

I’d like feedback on a possible typing construct tentatively called **`LiteralEnum`** , aimed at a common gap between `Enum/StrEnum` and `typing.Literal`.

**Problem**  
Many APIs use small, closed sets of scalar values (often strings: HTTP methods, event names, config keys). At runtime, these are most ergonomic as _plain literals_, but statically we want _exhaustiveness checking_.

Today this usually leads to duplication, e.g. a constants namespace plus a parallel `Literal[...]` union, or forcing callers to pass enum members instead of raw values.

**Proposed idea**  
`LiteralEnum` defines a finite, named set of literal values that:

- are plain runtime literals (`str`, `int`, `bool`, `None`, etc.),
- provide a runtime namespace, iteration, and validation, and
- are treated by type checkers as an exhaustive `Literal[...]` union.
- This is not intended to replace Enum or Literal, but to cover the narrow case where literal values themselves are the API surface.

Minimal example:

```python
from typing import LiteralEnum

class HttpMethod(LiteralEnum):
    GET = "GET"
    POST = "POST"
    DELETE = "DELETE"

def handle(method: HttpMethod) -> None:
    ...

handle("GET") # accepted
handle(HttpMethod.GET) # accepted
handle("git") # type checker error

```

At runtime:

- `HttpMethod.GET == "GET"`
- `list(HttpMethod) == ["GET", "POST", "DELETE"]`
- `"GET" in HttpMethod` can be used to check if a string is valid
- `HttpMethod("GET")` could optionally validate and return `"GET"` (acknowledging that callable classes usually construct instances)

At type-check time, `HttpMethod` is equivalent to:

```python
Literal["GET", "POST", "DELETE"]

```

Subclass extension is explicit (`extend=True`) to avoid accidental widening.

**Status**

- I have a small runtime prototype as a proof of concept (linked below, under 200 lines); it does not attempt to solve the type-checker side yet

- I’m interested in whether this direction seems:

Draft PEP (early): [LiteralEnum/PEP.md at master · modularizer/LiteralEnum · GitHub](https://github.com/modularizer/LiteralEnum/blob/master/PEP.md)  
Runtime prototype: [LiteralEnum/src/typing\_literalenum.py at master · modularizer/LiteralEnum · GitHub](https://github.com/modularizer/LiteralEnum/blob/master/src/typing_literalenum.py)

I’m not attached to the name or the source code, I’m looking to validate the _concept_ and scope before going further.

Questions for discussion:

1. Do other people feel this pain point as much as me?
2. Have you found yourself writing duplicate types: a (`Literal` plus an `Enum` or just a bare class with attributes)?
3. Are there alternative designs that could provide a runtime namespace and an exhaustive type hint, without introducing a new core typing construct?

Thanks for any feedback,  
Torin

---

<div class="post-metadata">

**Author:** ![jorenham](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jorenham/32/27806_2.png) [@jorenham](https://discuss.python.org/u/jorenham)\
**Post date:** [February 4, 2026, 10:01am UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/2 "2026-02-04T10:01:41Z")

</div>

So, it’s like a special case of the sum type?

---

<div class="post-metadata">

**Author:** ![Tinche](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tinche/32/12507_2.png) [@Tinche](https://discuss.python.org/u/Tinche)\
**Post date:** [February 4, 2026, 10:02am UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/3 "2026-02-04T10:02:31Z")

</div>

I understand the use case and think it might be good for developer ergonomics.

Currently, I just use literals directly. I check unstructured input using `cattrs.structure(method, Literal["GET", "POST"])`. This won’t be typesafe until the major typecheckers implement TypeForm, but at least there’s a path forward.

I wonder if the problem could be solved without adding a new, in-between combination of literal and enum, with the following changes:

- for each enum, flesh out the static argument type to ` __init__ ` (or I guess ` __new__ `, or whatever is called at runtime) to something like (for HttpMethod) `HttpMethod | Literal["GET", "POST"]`. This is the current reality, modulo some edge cases.
- introduce a way to reference the type of another Callable’s parameter. So you’d annotate the first parameter of `handle` as (spitballing) `method: ParamOf[HttpMethod]`. Maybe this can already be done with a clever decorator?

Then, your `handle` function’s `method` parameter would essentially have the type `HttpMethod | Literal["GET", "POST"]`.

---

<div class="post-metadata">

**Author:** ![randolf-scholz](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/randolf-scholz/32/11123_2.png) [@randolf-scholz](https://discuss.python.org/u/randolf-scholz)\
**Post date:** [February 4, 2026, 10:03am UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/4 "2026-02-04T10:03:38Z")

</div>

> 1. Do other people feel this pain point as much as me?

YES

> 1. Have you found yourself writing duplicate types: a (`Literal` plus an `Enum` or just a bare class with attributes)?

YES

> 1. Are there alternative designs that could provide a runtime namespace and an exhaustive type hint, without introducing a new core typing construct?

See earlier discussion here: [Amend PEP 586 to make `enum` values subtypes of `Literal` - #12 by randolf-scholz](https://discuss.python.org/t/amend-pep-586-to-make-enum-values-subtypes-of-literal/59456/12)

My idea was to amend the typing spec so that — at least for `IntEnum` and `StrEnum` — they would be considered subtypes of literal `int` and `str` values.

Your proposal may actually be an easier way to get something like this accepted, though I still don’t get why we would need a special type for this rather than supporting it natively on `IntEnum` and `StrEnum`. @Jelle gave an [example here](https://discuss.python.org/t/amend-pep-586-to-make-enum-values-subtypes-of-literal/59456/4) why this is generally unsafe, but I tested marking the integer / string interface of `IntEnum` / `StrEnum` with `@final` and [the `mypy-primer` results looked good](https://github.com/python/typeshed/pull/15121), so I don’t get why we can’t just special case `IntEnum` and `StrEnum` rather than inventing a new type for this.

---

<div class="post-metadata">

**Author:** ![tmk](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tmk/32/10935_2.png) [@tmk](https://discuss.python.org/u/tmk)\
**Post date:** [February 4, 2026, 11:35am UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/5 "2026-02-04T11:35:22Z")

</div>

I do find myself often writing something like

```python
from typing import Literal

type HttpMethod = Literal["GET", "POST", "DELETE"]
VALID_HTTP_METHODS: list[HttpMethod] = ["GET", "POST", "DELETE"]

def f(x: str):
    assert x in VALID_HTTP_METHODS
    reveal_type(x) # Type of "x" is "Literal['GET', 'POST', 'DELETE']"

```

So, something like your proposal would be welcome.

One thing I’m maybe a bit worried about is that any code that evaluates type annotations at runtime will have to special-case this construct in order to understand that it is equivalent to `Literal[...]`.

---

<div class="post-metadata">

**Author:** ![JamesParrott](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jamesparrott/32/10534_2.png) [@JamesParrott](https://discuss.python.org/u/JamesParrott)\
**Post date:** [February 4, 2026, 12:54pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/6 "2026-02-04T12:54:51Z")

</div>

They could be more ergonomic - I have certainly felt this pain point before. I ran some benchmarks on the particular library though, and convinced myself (possibly mistakenly) that enums were slower anyway and dropped them, instead going with the highly contrived:

```py
FieldTypeT = Literal["A", "B",]

class FieldType:

    A: Final = "A" 
    B: Final = "B"
    __members__ : set[FieldTypeT] = {
        "A",
        "B",
    }

```

---

<div class="post-metadata">

**Author:** ![peterc](https://avatars.discourse-cdn.com/v4/letter/p/f9ae1b/32.png) [@peterc](https://discuss.python.org/u/peterc)\
**Post date:** [February 4, 2026, 1:06pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/7 "2026-02-04T13:06:58Z")

</div>

You can also use the pattern

```python
from typing import Literal, get_args

HttpMethod = Literal["GET", "POST", "DELETE"]
VALID_HTTP_METHODS: tuple[HttpMethod, ...] = get_args(HttpMethod)

assert VALID_HTTP_METHODS == ("GET", "POST", "DELETE")

```

---

<div class="post-metadata">

**Author:** ![Dutcho](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/dutcho/32/7074_2.png) [@Dutcho](https://discuss.python.org/u/Dutcho)\
**Post date:** [February 4, 2026, 3:25pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/8 "2026-02-04T15:25:43Z")

</div>

Indeed, or with `type HttpMethod =` the slightly less ergonomic `get_args(HttpMethod. __value__ )`.

---

<div class="post-metadata">

**Author:** ![beauxq](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/beauxq/32/15042_2.png) [@beauxq](https://discuss.python.org/u/beauxq)\
**Post date:** [February 4, 2026, 5:28pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/9 "2026-02-04T17:28:31Z")

</div>

It might be nice if we could just do this:

```py
HttpMethod = Literal["GET", "POST", "DELETE"]

assert "GET" in HttpMethod
assert "GIT" not in HttpMethod

```

* * *

although, we would have to figure out what to do with something like this:

```py
HttpMethod = Literal["GET", "POST"] | Literal["DELETE"]

```

since that should be equivalent according to the type system.

---

<div class="post-metadata">

**Author:** ![modularizer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/modularizer/32/34039_2.png) [@modularizer](https://discuss.python.org/u/modularizer)\
**Post date:** [February 4, 2026, 5:34pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/10 "2026-02-04T17:34:50Z")

</div>

Kind of, yeah! A sum type says “this value is one of these options.” LiteralEnum is basically that, but specifically for plain values like strings and ints. The difference is LiteralEnum also gives you a nice way to look them up by name (like `HttpMethod.GET`), loop through them, and validate them — things a general sum type doesn’t give you out of the box.

---

<div class="post-metadata">

**Author:** ![modularizer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/modularizer/32/34039_2.png) [@modularizer](https://discuss.python.org/u/modularizer)\
**Post date:** [February 4, 2026, 6:04pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/11 "2026-02-04T18:04:16Z")

</div>

Thanks for all the feedback! lots of great ideas here. I want to respond to a few points individually, then step back and frame what I’m personally looking for.

**Quick responses:**

@jorenham : yes, you can think of it like that. The extra value over a general sum type is primarily namespace, iteration, and validation out of the box

@Tinche : the `ParamOf` idea is creative. It seems very useful and I love that it is general. Is not quite the first-class treatment that I think is worth considering for `LiteralEnum` proposal, but I see its value

@randolf-scholz : I like your PEP 586 amendment and think it solves an important direction: using `HttpMethod.GET` where `Literal["GET"]` is expected. I also understand Jelle’s response and see value in having `Literal` typehints only match true literals. The gap is the other direction — passing a plain `"GET"` to a function typed `method: HttpMethod` still fails. LiteralEnum tries to make both directions work, which cannot be done by modifying `Enum` ( it would break stuff )

@peterc : the `get_args` pattern is clean for getting runtime iterable from a `Literal`. The thing it’s missing is namespace access — there’s no `HttpMethod.GET` to write in code, and you still end up with two separate names to maintain.

@tmk : your `Final` + ` __members__ ` class is almost exactly the pattern that motivated this proposal! I think it is a great pattern in the current ecosystem, but I would love to see a pattern supporting a single source of truth in future versions of Python

@Dutcho : good point about `type HttpMethod = ...` requiring `get_args(HttpMethod. __value__ )`. Another example of how current tools make you choose between “nice for the type checker” and “nice at runtime.”

@beauxq : making `in` work on `Literal` directly would be fantastic. It would not solve all pain points, but I see that as a step in the right direction

* * *

**What I’m aiming for**

Today, getting everything I want requires something like three separate constructs:

```python
# A current pattern I think could be made MUCH better

FieldTypeT = Literal["A", "B"]

class FieldType:
    A: Final[Literal["A"]] = "A"
    B: Final[Literal["B"]] = "B"

FieldTypes: Iterable[FieldTypeT] = {"A", "B"}

```

…but it KILLS me that this has no single source of truth - every value is written three times.

I wanted to lay out my personal litmus tests for what I’d want from a solution. You are more than welcome to disagree with these goals and voice your own preferences. It would be interesting to hear where people draw different lines. For me:

1. **Namespace** for member access, e.g. `FieldType.A`
  - `Literal` fails this, and I see it as `Literal`’s biggest weakness

2. **Raw literals accepted** : `"A"` should be an acceptable input to a param typed as `t: FieldType`
  - `Enum/StrEnum` fail this and I see it as their biggest weakness for SOME use cases
  - NOTE: there are definitely times devs WANT to reject raw strings to avoid floating literals – I would not want to change `Enum/StrEnum` behavior here. I just think `LiteralEnum` should behae like a `Literal` here, not like an `Enum`

3. **Named members accepted** : `FieldType.A` should be an acceptable input to a param typed as `t: FieldType`
  - comparing an `Enum` member against a `Literal` type hint currently fails, and I think this is one thing @randolf-scholz was trying to address with his PEP 586 amendment

4. **Iteration and containment** : `x in FieldType` and `for x in FieldType` should be first-class
  - both `Literal` and `Enum` provide ways to do this, but it could be more natural (and as @beauxq suggested, even `Literal` could benefit from `in` support)

5. **Single source of truth** : if I have to write `"A"` more than once when defining my type, it fails this test
6. **One type, not two** : most current solutions require separate variables for different parts of the functionality, which I find error-prone

Here’s how the current approaches score:

| Approach | #1 Namespace | #2 Raw lit | #3 Member | #4 Iterate | #5 Single source | #6 One type that does it all |
| --- | --- | --- | --- | --- | --- | --- |
| `Literal` alone | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ |
| `Literal` + `get_args` (@peter) | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ |
| `StrEnum` | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ |
| `StrEnum` + PEP 586 amend (@Randolf) | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ |
| `Enum` + `ParamOf` (@Tinche) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| `Final` class + `Literal` alias (@tmk) | ✅ | ⚠ | ✅ | ⚠ | ❌ | ❌ |
| Runtime `in` on `Literal` (@beauxq) | ❌ | ✅ | ❌ | ⚠ | ✅ | ❌ |
| **LiteralEnum (proposed)** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |

As far as why I’m suggesting a new type rather than modifying an existing one:

- I don’t see a way to make `Enum` pass #2 without conflicting with code that intentionally requires enum members
- My suggestion is much closer to “`Literal` with namespace features” than it is to being an actual `Enum` (certainly open to a rename if that’s a point of tension)
- I don’t see a path to giving `Literal` namespace functionality. That would be a huge leap

---

<div class="post-metadata">

**Author:** ![randolf-scholz](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/randolf-scholz/32/11123_2.png) [@randolf-scholz](https://discuss.python.org/u/randolf-scholz)\
**Post date:** [February 4, 2026, 6:49pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/12 "2026-02-04T18:49:44Z")

</div>

There is an important property of StrEnum that’s not listed here: it subclasses str and enum members hash to the exact same values as the plain strings do. I’d want LiteralEnum to do the same.

In fact, if specced right (disallowing interface extensions on LiteralEnum), then this could allow nice things like type hinting a function argument with `dict[Field, Value]` or `TypedDict` with enum keys, while allowing callers to pass literal dicts satisfying the schema.

---

<div class="post-metadata">

**Author:** ![modularizer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/modularizer/32/34039_2.png) [@modularizer](https://discuss.python.org/u/modularizer)\
**Post date:** [February 4, 2026, 7:10pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/13 "2026-02-04T19:10:46Z")

</div>

@randolf-scholz you make a great point and that is definitely a key discussion point I am eager to get feedback on.

Should `FieldType.A` be …  
A. (Proposed) of type `str` (JUST the raw literal) or of  
B. (similar to StrEnum) having a type which is a subclass like `str, FieldType`?

My thoughts:

- I absolutely see value in what you are proposing, but for me, the value add is not enough to justify the added complication
- Your proposal would make `LiteralEnum` lean towards being more like `Enum` and less like `Literal`, that is totally fine, just an observation
- option B. has some niceties, but also may lead to a lack of trust and immediate recognition
  - when I see the subclassing, I immediately jump to “what broke?”
  - with a good implementation, the answer may very well be that absolutely nothing broke
  - BUT… if I do not have the time to verify myself, I don’t have the immediate trust
  - So… I wind up doing extra work like casting `str(HttpMethod.GET)`, etc. until I read the source code or get convinced

- I do not personally feel any pain points with the values not being an instance of the special type
  - If I wanted a `StrEnum` I could use one. It has value on its own, and yes maybe `StrEnum` could be improved by your PEP propsal or something similar

- I am more focused on building off of the functionality of `Literal` than on extending the functionality of `StrEnum`

While I lean towards continuing to propose option A, I would still be thrilled if option B gained traction, and would help advocate for it.

Do others see advantages of the members having a special type as opposed to being more like a namespace that retains the true raw literal type?

---

<div class="post-metadata">

**Author:** ![tmk](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tmk/32/10935_2.png) [@tmk](https://discuss.python.org/u/tmk)\
**Post date:** [February 4, 2026, 7:35pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/14 "2026-02-04T19:35:07Z")

</div>

Just a note: I think you wanted to tag @jamesparrott instead of me in the two places I’m tagged.

---

<div class="post-metadata">

**Author:** ![tmk](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/tmk/32/10935_2.png) [@tmk](https://discuss.python.org/u/tmk)\
**Post date:** [February 4, 2026, 8:21pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/15 "2026-02-04T20:21:11Z")

</div>

> [@beauxq](#):
>
> It might be nice if we could just do this:
> 
> ```python
> HttpMethod = Literal["GET", "POST", "DELETE"]
> 
> assert "GET" in HttpMethod
> assert "GIT" not in HttpMethod
> 
> ```

Maybe it could be modeled after `NewType`:

```python
from typing import SealedLiteralType

# single source of truth:
HttpMethod = SealedLiteralType("HttpMethod", ["GET", "POST", "DELETE"])

assert list(iter(HttpMethod)) == ["GET", "POST", "DELETE"]
assert "GET" in HttpMethod

def f(m: HttpMethod): ...
f("GET") # type checker: OK
f("PUT") # type checker: Error

```

---

<div class="post-metadata">

**Author:** ![modularizer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/modularizer/32/34039_2.png) [@modularizer](https://discuss.python.org/u/modularizer)\
**Post date:** [February 5, 2026, 12:55am UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/16 "2026-02-05T00:55:14Z")

</div>

I think the NewType-style factory suggestion is a clean mental model and would be an advancement for Python.

That said, the main thing I’m trying to preserve is a **stable runtime namespace** (`Foo.BAR`) as a **_single source of truth_** for the allowed literals.

For me that’s non-negotiable, because having an iterable typehint in no way eliminates the need to also have a namespace, and in current code it is not possible to have both using a single source of truth.

If the proposed type does not have namespace functionality, developers will inevitably need to create a second class or enum to maintain the namespace, leading to a second source of truth and lots of room for error.

So I’m very open to factory vs class vs hybrid _as long as the result is a namespaced container whose members are the canonical literals_.

Separately, just to avoid confusion about intent:

- I’ve put a small reference implementation on GitHub (`modularizer/LiteralEnum`), with a PyPI package of `literalenum` mainly so people can poke at the proposed runtime behavior if that’s helpful.
- I am **not** suggesting my source code gets adopted. I know that is not how this works and am sure someone else could right a narrower and cleaner implementation. However, I do like the runtime behavior which it shows
- That code **only handles runtime mechanics** today : it does not attempt to solve typing or checker integration in a meaningful way

Happy to adapt or discard the implementation entirely if the group converges on a better API shape.

---

<div class="post-metadata">

**Author:** ![pekkaklarck](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pekkaklarck/32/7211_2.png) [@pekkaklarck](https://discuss.python.org/u/pekkaklarck)\
**Post date:** [February 5, 2026, 12:18pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/17 "2026-02-05T12:18:20Z")

</div>

To get namespace support, would it be enough to enhance `Literal` so that you could do:

```python
State = Literal["ON", "OFF"]
assert State.ON == "ON"

```

The earlier mentioned

```python
assert value in State  

```

would be handy too.

I’d also love being able to do

```python
value: Literal = "ON"

```

to avoid repeating the value, but that’s not really related to this proposal.

---

<div class="post-metadata">

**Author:** ![modularizer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/modularizer/32/34039_2.png) [@modularizer](https://discuss.python.org/u/modularizer)\
**Post date:** [February 5, 2026, 5:08pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/18 "2026-02-05T17:08:55Z")

</div>

@pekkaklarck This is interesting. Looking back at the litmus tests I defined, it could potentially meet every one if it was combined with a suggestion like that from @beauxq and in your use case and many of mine it would indeed be useful.

However, I see some major conflicts:

```python
# 1. many sting literals are not legal variable names
TERMINAL_COLORS = Literal["\033[34m", "\033[0m"]
NUMBERING = Literal["1_a", "1_b"]

# 2. some string literals may conflict with important attributes and methods
DUNDER_NAMES = Literal[" __add__", " __sub__", " __class__", " __dict__"]

# 3. Many times the purpose of a namespace is to make lookups easier, so requiring key == value would be non-ideal
TRANSLATIONS_OF_FOOD = Literal["comida", "nourriture"]

# 4. possibly unexpected/unnecessary attribute on single string literals
X: Literal["x"] = "x" # just a bit odd because following the logic we would also have X.x == 'x'

```

I think the obvious response to this is to only do it for uppercase non underscored literals, and even potentially limit to when there is more than one item.

But that feels… odd? a bit non-intuitive?

However, it did inspire this idea using the walrus operator:

```python
HttpMethod = Literal[GET:= "GET", POST:= "POST"] # This SORTA works at runtime right now, defining locally-scoped non-namespaced variables of GET and POST, but fails on type checker's rules about literals

```

or using custom syntax

```python
HttpMethod = Literal[GET="GET",POST="POST"]
# or 
HttpMethod = Literal(GET="GET",POST="POST")

```

which when paired with

```python
assert "GET" in HttpMethod

```

could be pretty powerful

---

<div class="post-metadata">

**Author:** ![modularizer](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/modularizer/32/34039_2.png) [@modularizer](https://discuss.python.org/u/modularizer)\
**Post date:** [February 5, 2026, 5:27pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/19 "2026-02-05T17:27:15Z")

</div>

If I had to summarize thoughts here, it seems like a lot of the pushback centers around not wanting to add a new type to the standard library, and I think that is totally fair.

To clarify, the issue that I am trying to solve:

- is **not** that `LiteralEnum` or a similar thing is not in the standard library: that is fine. Let it prove itself useful first.
- I see the issue being that `LiteralEnum` or something similar **is not possible** in a way that behaves nicely with typehinting and maintains a single source or truth.

With that in mind:  
**Do you all see any potential support for a generic way to decorate or otherwise make a class with the behavior you wish to see from the type checkers?** A solution which allows developers to solve this painpoint related to enums but also hopefully many other pain points?

For instance: when used as a value, treat it as its true type, but when used as a typehint treat it as some specified or inferred static type?

```python
@static_type(Literal["GET", "POST"])
class HttpMethod:
    GET = "GET"
    POST = "POST"

```

That would not in and of itself allow a single source of truth, but might be extendable like

```python
@static_type(spec=InferSpec(kind=Literal, params="values"))
class HttpMethod:
    GET = "GET"
    POST = "POST"

```

It is a much broader ask so I see it as less likely but I would happy to be wrong.

---

<div class="post-metadata">

**Author:** ![hwelch](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hwelch/32/33920_2.png) [@hwelch](https://discuss.python.org/u/hwelch)\
**Post date:** [February 5, 2026, 6:19pm UTC](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000/20 "2026-02-05T18:19:28Z")

</div>

I feel like it would be nice to be able to just `Unpack` an into a Literal. Where the unpacked values must be marked as `Final`

```python
Methods = ('GET', 'POST', 'PATCH', 'DELETE')
Method = Literal[*Methods] # Type Error

Methods: Final = ('GET', 'POST', 'PATCH', 'DELETE')
Method = Literal[*Methods] # Ok

```

I don’t really see a clean way of combining Literals and Enums though, since an Enum requires the members to be valid variable names like you said.

You could also just have a new `LiteralEnum` abstract that enforces that all literal values are mapped to enum names:

```python
class MethodEnum(LiteralEnum[Method]): # Type Error (Missing 'DELETE')
    get='GET'
    post='POST'
    patch='PATCH'

```

[Next page](https://discuss.python.org/t/proposal-literalenum-runtime-literals-with-static-exhaustiveness/106000.md?page=2)
