"Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why)." That's Tim Peters, in one of the most-quoted Python aphorisms ever written. It's also the rule that makes this entry honest: most Python developers never write a metaclass, never read one, and never miss them. But "what metaclasses actually are" is the highest-voted Python question on Stack Overflow (over 7,500 votes), and the topic gets misexplained more often than almost any other concept. This guide demystifies the underlying idea (classes are first-class objects, and metaclass is the class of a class), shows the simpler tools that replaced 95% of historical metaclass use (especially __init_subclass__ from PEP 487), and identifies the 3 genuine cases where you still need one. One of 10 explainers in our Python OOP complete guide.

Key Takeaways

  • A metaclass is the class of a class. Default metaclass is type; every class you write is an instance of it.
  • The triangle: instance is an instance of class, class is an instance of metaclass, and type.__class__ is type itself.
  • Tim Peters' rule: if you wonder whether you need a metaclass, you don't.
  • PEP 487 __init_subclass__ replaces 95% of historical metaclass use cases. Class decorators replace most of the rest.
  • Genuine metaclass cases: ABC mechanism (ABCMeta), Django and SQLAlchemy ORM models, Enum types. Application code rarely needs one.
The metaclass triangle: instance, class, metaclass, and where the recursion stops The metaclass triangle: where the recursion stops INSTANCE · CLASS · METACLASS · TYPE.__CLASS__ == TYPE LEVEL 1: INSTANCE p = Point(3, 4) an object what most code lives at __class__ LEVEL 2: CLASS class Point an object too controls instances __class__ LEVEL 3: METACLASS type controls classes where the recursion stops type.__class__ == type WHAT EACH LEVEL CONTROLS METHODS IN A CLASS def greet(self): return f"Hi {self.name}" → operate on the INSTANCE runs when you call p.greet() METHODS IN A METACLASS def __new__(mcs, name, bases, ns): # rewrite the class body → operate on the CLASS runs when the class is created TIM PETERS' RULE "Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't." If you can solve it with __init_subclass__, a class decorator, or a descriptor, do that instead.
Three levels, one self-loop. Methods in a class shape instances; methods in a metaclass shape classes.

Classes Are Objects Too

The starting insight: in Python, classes are themselves objects. You can pass a class as a function argument, return it from a function, store it in a variable, ask it about its attributes. Most languages treat classes as second-class citizens (compile-time templates). Python treats them as first-class runtime objects.
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

# Class is a real object you can manipulate:
print(Point)                # <class '__main__.Point'>
print(type(Point))          # <class 'type'>
also_point = Point          # Bind the class to another name
p = also_point(3, 4)        # Works exactly like Point(3, 4)
The line that matters: type(Point) returns type. The class Point is an instance of the built-in type. That's what makes type a metaclass: it's the class whose instances are themselves classes.

The Two Forms of type()

type has two completely different jobs depending on how you call it. The PSF Data Model reference documents both.

type(obj): the inspector

Called with one argument, type returns the class of the object:
print(type(42))             # <class 'int'>
print(type("hello"))        # <class 'str'>
print(type(Point(3, 4)))    # <class '__main__.Point'>
print(type(Point))          # <class 'type'>
This is the form most Python developers know.

type(name, bases, dict): the constructor

Called with three arguments, type creates a brand new class:
Point = type("Point", (), {
    "__init__": lambda self, x, y: setattr(self, "x", x) or setattr(self, "y", y),
    "describe": lambda self: f"({self.x}, {self.y})",
})

p = Point(3, 4)
print(p.describe())   # (3, 4)
print(type(p))        # <class '__main__.Point'>
What just happened: type called with a name string, a tuple of base classes, and a namespace dict, returned a new class. This is what Python does internally every time you write class Point:. The class statement is sugar for type with three arguments.What Metaclasses Actually Are in Python (and When You Genuinely Need One) - 1

Writing a Custom Metaclass

A custom metaclass inherits from type and overrides one of two methods: __new__ (creates the class) or __init__ (initializes the class after creation). Here's a registry metaclass that tracks every subclass:
class RegistryMeta(type):
    registry = {}

    def __new__(mcs, name, bases, namespace):
        cls = super().__new__(mcs, name, bases, namespace)
        if name != "Plugin":
            mcs.registry[name] = cls
        return cls

class Plugin(metaclass=RegistryMeta):
    pass

class EmailPlugin(Plugin):
    def send(self, msg): pass

class SMSPlugin(Plugin):
    def send(self, msg): pass

print(RegistryMeta.registry)
# {'EmailPlugin': <class 'EmailPlugin'>, 'SMSPlugin': <class 'SMSPlugin'>}
What happened: every time a class inherits (directly or indirectly) from Plugin, Python uses RegistryMeta to create it, which intercepts the creation and adds the new class to a registry. The framework code can later iterate RegistryMeta.registry to find all plugins. This is the classic "auto-registering subclasses" pattern.

The Much Simpler Alternative: __init_subclass__

The same registry, without a metaclass, using PEP 487's __init_subclass__ hook:
class Plugin:
    registry = {}

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Plugin.registry[cls.__name__] = cls

class EmailPlugin(Plugin):
    def send(self, msg): pass

class SMSPlugin(Plugin):
    def send(self, msg): pass

print(Plugin.registry)
# {'EmailPlugin': <class 'EmailPlugin'>, 'SMSPlugin': <class 'SMSPlugin'>}
Same behavior, half the conceptual overhead, no metaclass inheritance, no metaclass conflicts to worry about with multiple inheritance. PEP 487 (Python 3.6+) introduced __init_subclass__ precisely because the registry pattern was the most common metaclass use case and it deserved a simpler tool. The PEP authors estimate __init_subclass__ replaces 95% of historical metaclass usage.

The rule of thumb: if your goal is "run code every time my class is subclassed", reach for __init_subclass__. If your goal is "transform a specific class once", reach for a class decorator. Metaclasses come last.

Class Decorators: The Other Alternative

For one-time class transformation, a class decorator does what a metaclass would, with less ceremony:
def with_logging(cls):
    original_init = cls.__init__

    def logged_init(self, *args, **kwargs):
        print(f"Creating {cls.__name__} with {args}, {kwargs}")
        original_init(self, *args, **kwargs)

    cls.__init__ = logged_init
    return cls

@with_logging
class Order:
    def __init__(self, items):
        self.items = items

o = Order(["apple", "pear"])
# Creating Order with (['apple', 'pear'],), {}
The decorator runs once when the class is defined. It modifies the class and returns it. No metaclass inheritance, no impact on subclasses. Class decorators are the right tool when you want to transform exactly one class.

What Metaclasses Genuinely Add

If __init_subclass__ and decorators cover 95% of cases, what's left for metaclasses? Three real categories:

1. Controlling class creation itself

A metaclass's __new__ runs BEFORE the class object exists. You can validate the class body, reject the class entirely, or fundamentally rewrite it. __init_subclass__ runs AFTER class creation, so it can't do these things. The ABC machinery (abc.ABCMeta) needs this power to validate that subclasses implement all abstractmethods at instantiation time.

2. Customizing class-level operations

A metaclass can define __getattr__, __call__, or __iter__ that operate on the CLASS itself, not on instances. Enum types use this: Color.RED works because EnumMeta overrides class-level attribute lookup. You couldn't do this with __init_subclass__ because by the time the subclass exists, the lookup behavior is already set by type.

3. Translating declarative class bodies

Django's ORM and SQLAlchemy use metaclasses to translate declarations like name = models.CharField(max_length=100) into actual database column descriptors and table schemas. The metaclass intercepts each attribute assignment in the class body, replaces it with the bound descriptor, registers the class with the framework's table registry, and validates that required attributes exist. This translation has to happen at class creation time, which is exactly what metaclasses control.

Real-World Example: Django Model

A simplified version of what happens when Django's models.Model is subclassed:
class ModelMeta(type):
    def __new__(mcs, name, bases, namespace):
        # Skip the base class itself
        if name == "Model":
            return super().__new__(mcs, name, bases, namespace)

        # Collect Field instances from the class body
        fields = {key: val for key, val in namespace.items()
                  if isinstance(val, Field)}

        # Generate __init__ that accepts the field names
        def __init__(self, **kwargs):
            for fname in fields:
                setattr(self, fname, kwargs.get(fname))
        namespace["__init__"] = __init__

        # Register the resulting class
        cls = super().__new__(mcs, name, bases, namespace)
        cls._meta = {"fields": fields, "table_name": name.lower()}
        return cls

class Field:
    def __init__(self, max_length=None):
        self.max_length = max_length

class Model(metaclass=ModelMeta):
    pass

class User(Model):
    name = Field(max_length=100)
    email = Field(max_length=200)

u = User(name="Alice", email="a@b.com")
print(u.name, u.email)         # Alice a@b.com
print(User._meta["fields"])    # {'name': <Field>, 'email': <Field>}
The metaclass intercepts the class creation, scans the namespace for Field instances, generates a custom __init__, and attaches metadata. Application code writes class User(Model): with simple declarations, and the metaclass does the heavy lifting. Real Django does much more, but the pattern is identical.

Mini-Example: Enum as a Metaclass Use Case

The standard library's Enum uses EnumMeta to intercept class-level attribute lookup so that Color.RED returns an enum member rather than the raw value. A simplified version of the same pattern:
class SimpleEnumMeta(type):
    def __new__(mcs, name, bases, namespace):
        # Find all uppercase attributes in the class body
        members = {key: val for key, val in namespace.items()
                   if key.isupper() and not key.startswith("_")}

        cls = super().__new__(mcs, name, bases, namespace)
        cls._members = members
        return cls

    def __iter__(cls):
        return iter(cls._members.values())

    def __len__(cls):
        return len(cls._members)

class Color(metaclass=SimpleEnumMeta):
    RED = 1
    GREEN = 2
    BLUE = 3

print(Color.RED)         # 1
print(list(Color))       # [1, 2, 3]  — iterating the CLASS, not an instance
print(len(Color))        # 3
The crucial trick: __iter__ and __len__ defined on the metaclass operate on the class itself. list(Color) iterates over the class because the metaclass's __iter__ handles it. __init_subclass__ can't do this because it only runs after the class exists; the special methods invoked on the class object itself must live on the metaclass.

This is the third genuine category mentioned earlier. Real EnumMeta does much more (member value uniqueness, member name binding, hash and equality customization), but the pattern is identical: a metaclass that customizes what the class itself supports.

The Metaclass Conflict Trap

One reason to avoid metaclasses when possible: they don't combine cleanly with multiple inheritance. If two parent classes use different metaclasses, Python raises TypeError at class creation:
class MetaA(type): pass
class MetaB(type): pass

class A(metaclass=MetaA): pass
class B(metaclass=MetaB): pass

class C(A, B): pass
# TypeError: metaclass conflict: the metaclass of a derived class
# must be a (non-strict) subclass of the metaclasses of all its bases
The fix is to define a combined metaclass that inherits from both MetaA and MetaB, but this only works if the metaclasses themselves are designed to cooperate. Frameworks that use metaclasses heavily (Django, SQLAlchemy) have well-known compatibility issues when combined with each other or with ABCs. __init_subclass__ doesn't have this problem; class-level hooks combine cleanly.

When __init_subclass__ vs Metaclass vs Decorator

NeedReach forWhy
Run code every time a subclass is defined__init_subclass__PEP 487's exact purpose, no metaclass conflicts
Transform a single class onceClass decoratorOne-shot, explicit, doesn't propagate
Customize attribute behavior on instancesDescriptors or @propertyCovered in the @property guide
Validate that a class meets a contract at instantiationABC + @abstractmethodThe ABC guide covers this
Control class-level attribute lookup (like Enum.RED)MetaclassOnly metaclasses see class-level attribute access
Translate declarative class bodies (ORMs)MetaclassNeed to intercept the class-creation call itself
Reject the class entirely under some conditionMetaclassOnly __new__ on metaclass can refuse to create the class

Common Mistakes

1. Reaching for a metaclass when __init_subclass__ would do

The most frequent mistake. If you can phrase your need as "do X when someone subclasses my class", use __init_subclass__. Metaclasses propagate through the inheritance chain in ways that create conflicts later.

2. Confusing metaclass with abstract base class

An ABC is a regular class with abstract methods, designed to be subclassed. A metaclass is the class of a class. They're related (ABCMeta IS a metaclass), but the user-facing tool is different: you usually inherit from abc.ABC, not from a custom metaclass.

3. Overriding __new__ vs __init__ in the metaclass

__new__ runs first and creates the class object; __init__ runs after and can modify it. If you want to change WHAT class is returned (rare), override __new__. If you just want to set attributes on the created class, __init__ or even __init_subclass__ is enough.

4. Forgetting to call super() in metaclass __new__

Without super().__new__(mcs, name, bases, namespace), you don't get a real class back. The result is unusable. Always start with cls = super().__new__(...) and modify cls from there.

5. Trying to combine metaclasses across libraries

If you're using Django models with SQLAlchemy mixins, or ABCs with a custom metaclass, you'll hit metaclass conflict errors. The fix is usually to drop one library's metaclass approach in favor of plain classes plus __init_subclass__.

Frequently Asked Questions

What is a metaclass in Python?

A metaclass is the class of a class. In Python every class is itself an instance of some metaclass, and by default that metaclass is type. The relationship has three levels: an instance is an instance of its class, and that class is an instance of its metaclass. Metaclasses control how classes are created and behave, while regular classes control how instances are created and behave. The default type metaclass handles every class you write unless you specify otherwise with metaclass=YourMeta in the class definition. Most Python developers never need to write a metaclass; the standard library provides them for ABCs and enums, and frameworks like Django and SQLAlchemy use them for declarative model classes, but application code rarely benefits.

When should I use a metaclass in Python?

Almost never in application code. Tim Peters captured the rule: "Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't." For modifying subclasses, PEP 487 added __init_subclass__ in Python 3.6, which replaces 95% of metaclass use cases more cleanly. For transforming a single class, class decorators are usually enough. Metaclasses are genuinely needed only when you must control class creation itself (rare): ABC machinery via ABCMeta, ORM declarative classes like Django Model and SQLAlchemy Base that need to translate class-body declarations into descriptors, and Enum types that intercept attribute lookup on the class. Outside those well-known cases, prefer the simpler alternatives.

What is the difference between type and metaclass in Python?

type IS the default metaclass. It serves two roles depending on how you call it: type(obj) with one argument returns the class of obj (acting as an inspector), while type(name, bases, dict) with three arguments creates a new class (acting as a constructor). When you write a normal class definition with class MyClass:, Python internally calls type with the name MyClass, the base classes, and a dict of the class body. A custom metaclass is a class that inherits from type and overrides its methods (typically __new__ or __init__) to customize class creation. The recursion bottoms out with type.__class__ equal to type itself.

What does __init_subclass__ do and how does it replace metaclasses?

__init_subclass__ (PEP 487, Python 3.6+) is a classmethod called automatically every time a class inherits from the class defining it. The new subclass is passed as cls, plus any keyword arguments from the class definition. This covers the most common metaclass pattern: "run code every time my class gets subclassed", without inheritance of a custom metaclass and without the metaclass-conflict headaches that come with multiple inheritance. PEP 487 cites three categories that previously required metaclasses (post-creation initialization, descriptor setup, attribute order tracking) and notes that the first two are fully replaceable by __init_subclass__. Reach for it before reaching for a metaclass.

Why are Django models and SQLAlchemy classes considered metaclass examples?

Both frameworks need to translate class-body declarations (like name = models.CharField()) into runtime structures (database column descriptors, table schemas, ORM mappings). This translation has to happen at class-creation time, BEFORE any instance exists, so the framework can register the class with its registry and generate the SQL schema. A metaclass intercepts the class-creation call and rewrites the class body: replacing field descriptors with bound versions, registering the class with the framework's registry, and validating that required attributes are present. This is one of the few cases where metaclasses are the simplest tool; rewriting class-body declarations cleanly is hard with __init_subclass__ alone because the framework needs to control how attribute assignment in the class body works.

The Bottom Line: Understand Them, Avoid Writing Them

Metaclasses are real: every class in Python is an instance of one, and type is the default. Understanding the triangle (instance is an instance of class, class is an instance of metaclass) demystifies a lot of Python internals: why type(obj) works, why ABCs can block instantiation, why Django models can magically map class bodies to database tables. But writing your own metaclass is rarely the right answer. PEP 487's __init_subclass__ replaces 95% of historical use cases more cleanly; class decorators handle most of the rest. Reserve metaclasses for the three genuine scenarios (controlling class creation, customizing class-level operations, translating declarative bodies). Tim Peters' rule still holds: if you wonder whether you need one, you don't. With this guide complete, browse the full Python OOP guide for the full series.

Master the OOP Toolkit Before Reaching for Metaclasses

CodeGym's Python track works through the full OOP spectrum across 62 levels and 800+ tasks: classes, inheritance, decorators, descriptors, ABCs, dataclasses, and finally metaclasses for the few cases that genuinely need them. AI validators catch the easy traps (forgetting super() in __new__, metaclass conflicts in multiple inheritance); AI mentors explain when a custom metaclass is the right tool versus when __init_subclass__ would do. First level free; full plan on the pricing page.