Fix TypeError: 'type' object is not subscriptable in Python Type Hints

beginner🐍 Python2026-06-19| Python 3.8 and earlier, any OS (Windows / macOS / Linux)

Error Message

TypeError: 'type' object is not subscriptable
#python#type-hints#typeerror#typing#python38#generics

TL;DR Quick Fix

On Python 3.8 or older, built-in types like list[int] and dict[str, int] can't be used as generic type hints directly. Two fast escapes: swap to typing module equivalents, or drop from __future__ import annotations at the top of your file.

# Breaks on Python < 3.9
def get_scores(names: list[str]) -> dict[str, int]:
    return {name: 0 for name in names}

# Fix 1: typing module (works back to Python 3.5)
from typing import List, Dict

def get_scores(names: List[str]) -> Dict[str, int]:
    return {name: 0 for name in names}

# Fix 2: lazy annotations (works back to Python 3.7)
from __future__ import annotations

def get_scores(names: list[str]) -> dict[str, int]:
    return {name: 0 for name in names}

What Causes This Error

PEP 585, shipped in Python 3.9, added native generic support to built-in types. Before that, list and dict didn't support the subscript operator ([]) at runtime. Only the wrapper classes in the typing module β€” List, Dict, and friends β€” knew how to handle it.

By default, Python evaluates annotations at import time. The moment it hits list[int] on an older interpreter, it tries to subscript the raw list type β€” and blows up immediately. Common triggers:

  • Function signatures: def foo(x: list[int])
  • Variable annotations: scores: dict[str, float] = {}
  • Dataclass field definitions using PEP 585 syntax
  • Pydantic or attrs models running on Python 3.8

Not sure which Python you're running? Check fast:

python --version
# Or inside your script:
import sys
print(sys.version_info)  # e.g., sys.version_info(major=3, minor=8, micro=18, ...)

Fix Approaches

Option 1: Import from the typing module (safest for libraries)

Swap the bare built-in names for their uppercase counterparts from typing. Verbose, yes β€” but it works all the way back to Python 3.5 and plays nicely with every tool in the ecosystem.

from typing import Dict, FrozenSet, List, Optional, Set, Tuple, Type

def process(items: List[int]) -> Tuple[int, ...]:
    return tuple(items)

def lookup(mapping: Dict[str, List[str]]) -> Optional[str]:
    return mapping.get("key", [None])[0]

Quick cheat-sheet for the types you'll reach for most often:

# Python < 3.9          β†’ Python 3.9+
List[int]               β†’ list[int]
Dict[str, int]          β†’ dict[str, int]
Tuple[int, ...]         β†’ tuple[int, ...]
Set[str]                β†’ set[str]
FrozenSet[str]          β†’ frozenset[str]
Type[MyClass]           β†’ type[MyClass]
Optional[str]           β†’ str | None  (3.10+)

Option 2: from future import annotations

One import, zero annotation changes. This line makes Python store all annotations as strings rather than evaluating them at runtime β€” so you can write PEP 585 syntax freely on Python 3.7+.

from __future__ import annotations

def merge(a: list[str], b: list[str]) -> dict[str, int]:
    return {k: i for i, k in enumerate(a + b)}

For large codebases with hundreds of files, this is the quickest win β€” no hunt-and-replace across imports. One catch: libraries that introspect annotations at runtime (FastAPI's dependency injection, serializers like cattrs) will receive strings instead of real type objects, and may need extra handling.

Option 3: Upgrade to Python 3.9+

If you control the runtime, this is the cleanest long-term path. Python 3.9 made built-in generics first-class citizens β€” no imports, no workarounds.

# Python 3.9+ β€” no imports needed
def summarize(data: list[dict[str, int]]) -> list[int]:
    return [sum(d.values()) for d in data]

Bonus: dataclass fields

Dataclasses are a sneaky trigger. Unlike function annotations, field annotations are evaluated at class definition time β€” so the error hits on import, not on function call.

# Fails on Python 3.8
from dataclasses import dataclass

@dataclass
class Report:
    scores: dict[str, int]   # TypeError right here, at import time
    tags: list[str]

# Fix: one future import is all you need
from __future__ import annotations
from dataclasses import dataclass

@dataclass
class Report:
    scores: dict[str, int]   # Fine now
    tags: list[str]

Verifying the Fix

Run your module directly. A clean import means you're done:

python my_module.py

For a quicker check without running the whole script:

python -c "from my_module import get_scores; print(get_scores(['alice', 'bob']))"

Want to confirm the annotations are well-formed? Inspect them directly:

import inspect
import my_module
print(inspect.signature(my_module.get_scores))
# Output: (names: List[str]) -> Dict[str, int]

Further Reading

Related Error Notes