# Typing feature to statically get all subclasses of class

**URL:** <https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671>\
**Category:** Ideas\
**Tags:** typing\
**Created:** [August 20, 2026, 6:40pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671 "2026-08-20T18:40:02Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![JoniKauf](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jonikauf/32/28765_2.png) [@JoniKauf](https://discuss.python.org/u/JoniKauf)\
**Post date:** [August 20, 2026, 6:40pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671/1 "2026-08-20T18:40:02Z")

</div>

I sometimes find myself with this problem:

```py

class Base: # Possibly an ABC
    ...

class SubA(Base):
    ...

class SubB(Base):
    ...

```

For example with custom exceptions, base ast nodes and so on.

Now I often want to use exhaustive pattern matching while excluding the base class, since it is often abstract.

In this case, I often find myself missing some way to describe “all subclasses of a type”. In this case, I would usually have to do:

```py

... # Code from before

type AllSubclassesT = SubA | SubB

# And then I can exhaustively match:

def func_that_handles_all(sub: AllSubclassesT) -> Any:
    match sub:
        case SubA():
            ...
        case SubB():
            ...
        case _:
            assert_never(sub)

```

If I add another subclass to my possibly long list of subclasses, I could easily forget it in the type alias and therefore my type checker won’t help me with handling all cases.

So for this case, a typing solution could be useful. It would scan the whole code for any class that subclass `Base` and then give you that statically as a union. Obviously, this wouldn’t work for dynamic class creation, but that is limited for static typing in many cases either way and not the main use case for this.

So basically:

```py

...

from typing import SubclassesOf

type AllSubclassesT = SubclassesOf[Base] # SubA | SubB

```

Returning a tuple instead of a union is also an idea I had, but I’m pretty sure unions make all things possibly that tuples would make possible, but not vice versa.

The result of this new type could not be a tuple of any specific order, for example `tuple[SubA, SubB]` since the type checker CANNOT know the order of **subclasses** which this would most likely be based off and therefore it would be ambiguous. Therefore `tuple[SubA | SubB, ...]` is the best type hint we can produce. But we can just do `tuple[SubclassesOf[Base], ...]` of the union result version and have this case included. Going from a tuple to union is (I think) not possible currently.

What do you think? Do you think this is feasible (especially to scan all files for classes or another idea)?

I just wanted to share the idea since I had this problem before.

---

<div class="post-metadata">

**Author:** ![JoniKauf](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/jonikauf/32/28765_2.png) [@JoniKauf](https://discuss.python.org/u/JoniKauf)\
**Post date:** [August 20, 2026, 6:41pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671/2 "2026-08-20T18:41:07Z")

</div>

Oh yeah I also didn’t mention recursive subclasses in this post yet, that would be another issue to solve. I think the base idea should be tackled first though.

---

<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:** [August 20, 2026, 6:57pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671/3 "2026-08-20T18:57:44Z")

</div>

I’m afraid this won’t work because Python’s type system is isn’t closed-world, so type-checkers can’t reliably determine all of the subclasses that exist. One way around this could be by adding support for sealed classes from e.g. [Draft PEP: Sealed decorator for static typing](https://discuss.python.org/t/draft-pep-sealed-decorator-for-static-typing/49206), but this proposal seems to have stranded.

---

<div class="post-metadata">

**Author:** ![NeilGirdhar](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/neilgirdhar/32/5776_2.png) [@NeilGirdhar](https://discuss.python.org/u/NeilGirdhar)\
**Post date:** [August 20, 2026, 7:52pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671/4 "2026-08-20T19:52:27Z")

</div>

> [@JoniKauf](#):
>
> If I add another subclass to my possibly long list of subclasses, I could easily forget it in the type alias and therefore my type checker won’t help me with handling all cases.
> 
> So for this case, a typing solution could be useful.

Makes sense, but this may be a design error. Why not make the function into an abstract method and put the code for each subclass into its derived method?

---

<div class="post-metadata">

**Author:** ![petercordia](https://avatars.discourse-cdn.com/v4/letter/p/bb73d2/32.png) [@petercordia](https://discuss.python.org/u/petercordia)\
**Post date:** [August 20, 2026, 7:55pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671/5 "2026-08-20T19:55:24Z")

</div>

I don’t do this for subclasses, but I have a pattern you can use:

1. create an exhaustive list somewhere of all options
2. in your CI/DI pipeline, assert that the list is exhaustive

To me using unit tests is the most natural place to put that assert. But I think if you really wanted to you might be able to make static type checking do it somehow.

To me the most “natural” way to achieve this\[1\] is to use a metaclass, to assert that the class is a member of `AllSubClassesT. __args__ `  
Then your code fails at import time if you define the subclass without updating the union.

* * *

1. making your CI/DI pipeline pick up on it that you’ve forgotten to update your exhaustive list

---

<div class="post-metadata">

**Author:** ![petercordia](https://avatars.discourse-cdn.com/v4/letter/p/bb73d2/32.png) [@petercordia](https://discuss.python.org/u/petercordia)\
**Post date:** [August 20, 2026, 7:58pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671/6 "2026-08-20T19:58:04Z")

</div>

Actually, I believe you can “just” use ` __init_subclass__ `

---

<div class="post-metadata">

**Author:** ![warden](https://avatars.discourse-cdn.com/v4/letter/w/13edae/32.png) [@warden](https://discuss.python.org/u/warden)\
**Post date:** [August 20, 2026, 8:12pm UTC](https://discuss.python.org/t/typing-feature-to-statically-get-all-subclasses-of-class/108671/7 "2026-08-20T20:12:56Z")

</div>

I am not trying to argue against your proposal, but if you aren’t aware, you can always do a runtime check:

```python
assert not (x := (
    set(Base. __subclasses__ ())
  - set(AllSubclassesT.evaluate_value(). __args__ )
)), x

```

I ran into a similar issue (although not with sub-classes, but all NamedTuple’s defined in a particular module).
