I am working with a generic class in python. The corresponding TypeVar is restricted to a finite amount of (invariant) types. Because it is of some importance what exact type it is at runtime, I specify the type at initialization. Later, I have some code where I want to narrow to certain types. Because I want to narrow to this specific type, the natural way seems to use [stored_type] is [desired_type]. Unfortunately, mypy as well as pyright do not perform any narrowing. However, if I use isinstance([stored_type], type([desired_type]), it narrows as intended. Also, a similar case where I use a Union instead, the narrowing using is works. I am currently using isinstance because it works for the type checker, but as far as I know is provides the stronger check here and is what I actually want. Is there a good reason for the current behaviour? Why is the narrowing with is less strict than with isinstance? from typing import reveal_type class MyClass1: def __init__(self): pass class MyClass2: def __init__(self, arg: int): pass class MyGeneric[V: (MyClass1, MyClass2)]: def __init__(self, member_type: type[V]): if member_type is MyClass1: reveal_type(member_type) # type[V@MyGeneric] if isinstance(member_type, type(MyClass1)): reveal_type(member_type) # type[MyClass1]* def mymethod(self, member_type: type[MyClass1] | type[MyClass2]): if member_type is MyClass1: reveal_type(member_type) # type[MyClass1] Continue reading...