Dataclasses and non-dataclasses inheritance

As far as I can tell your examples show the behaviour I’d expect.

This seems to be more to do with forgetting to use the @dataclass decorator, as the dataclass attribute you’re checking isn’t defined on the child class, so it’s looked up on the parents according to the MRO.

In your examples both DC1 and DC2 have __dataclass_fields__. DC1’s is empty and DC2’s has one entry. In C2’s MRO, DC1 comes before DC2 so you get the attribute from DC1 which is empty while in C3’s MRO, DC2 comes first so you get its attribute with 1 entry.

When you decorate the child class with @dataclass it does its own resolution checking for fields from parent classes and defines its own __dataclass_fields__ so it’s not retrieved from the parents any more.


You can’t really prevent people from forgetting to use the @dataclass decorator just by virtue of it being a decorator. The class is first constructed as a non-dataclass and then the @dataclass decorator converts it so a parent class can’t check if a child is a dataclass because initially it won’t be.

If you want to make sure that everything in the inheritance tree is a dataclass your best bet is probably to wrap dataclass in an __init_subclass__ method (providing you don’t use slots=True) along with a check that every class in the MRO (except object) is a dataclass and then use that class as your base class instead of using @dataclass directly. You should be able to use typing.dataclass_transform with this to make static tools behave.