Python issubclass with Generic Aliases

Python's built-in issubclass() function does not support parameterized generic aliases, raising a TypeError when evaluated against them in either argument position. Generic aliases—such as list[int] or dict[str, Any] introduced via PEP 585 and typing constructs—are intended primarily for static analysis and type hinting rather than runtime inheritance checks. Because generic type parameters undergo type erasure and do not represent distinct runtime types, standard subclass validation cannot inspect their nested parameters.

Generic Alias as the Target (classinfo)

When a parameterized generic alias is passed as the second argument to issubclass(), Python immediately raises an exception.

issubclass(list, list[int])
# TypeError: Subscripted generics cannot be used with class and instance checks

Python explicitly disallows checking whether a base type or specialized type inherits from a subscripted generic. This check is rejected because generic types rely on runtime type erasure. Validating a subscripted generic at runtime would require either shallow inspections that discard type safety or recursive item checks that introduce severe performance degradation.

Generic Alias as the First Argument

When a generic alias is provided as the first argument, issubclass() also fails because a generic alias is not an instance of type.

issubclass(list[int], list)
# TypeError: issubclass() arg 1 must be a class

At runtime, an expression like list[int] instantiates types.GenericAlias (or typing._GenericAlias), which acts as a wrapper around the origin type and its type arguments. Because issubclass() requires its first parameter to be a true class object (a subtype of type), evaluating the alias directly results in a validation error.

Why Runtime Generics Fail in issubclass()

  1. Type Erasure: Python collections do not retain runtime guarantees about the types of items they hold. A list[int] at runtime is simply a list.
  2. Variance and Invariance: Standard runtime inheritance does not account for generic variance rules. For instance, determining whether list[int] is a subclass of list[object] requires structural subtype evaluation that standard type.__subclasses__ mechanisms do not handle.
  3. Metaclass Separation: Generic aliases are factory metadata containers rather than new classes generated dynamically in the hierarchy.

Inspecting Generic Aliases Correctly

To perform subclass checks on generic types, you must unpack the underlying origin class using typing.get_origin().

from typing import get_origin

alias = list[int]
origin = get_origin(alias)  # Returns <class 'list'>

if origin is not None:
    print(issubclass(origin, collections.abc.Sequence))  # True

Extracting the origin drops the generic arguments (e.g., int) and returns the base class (e.g., list), enabling standard runtime type and subclass evaluation. For complex runtime checks against nested parameters, dedicated third-party runtime validation libraries such as typeguard or beartype should be used instead of issubclass().