{"record":{"id":"d6c2507268c590a8","repo":"hibernate/hibernate-orm","slug":"type-is-annotated-both-entity-and-mapped","errorCode":null,"errorMessage":"Type '{}' is annotated both '@Entity' and '@MappedSuperclass'","messagePattern":"Type '(.+?)' is annotated both '@Entity' and '@MappedSuperclass'","errorType":"exception","errorClass":"AnnotationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java","lineNumber":287,"sourceCode":"\t\tif ( context.getMetadataCollector().getClassType( classDetails ) == ENTITY ) {\n\t\t\tbindEntityClass( classDetails, inheritanceStatePerClass, context );\n\t\t}\n\t}\n\n\tprivate static void handleImport(ClassDetails annotatedClass, MetadataBuildingContext context) {\n\t\tif ( annotatedClass.hasDirectAnnotationUsage( Imported.class ) ) {\n\t\t\tfinal String qualifiedName = annotatedClass.getName();\n\t\t\tfinal String name = unqualify( qualifiedName );\n\t\t\tfinal String rename = annotatedClass.getDirectAnnotationUsage( Imported.class ).rename();\n\t\t\tcontext.getMetadataCollector().addImport( rename.isBlank() ? name : rename, qualifiedName );\n\t\t}\n\t}\n\n\tprivate static void detectMappedSuperclassProblems(ClassDetails annotatedClass) {\n\t\tif ( isMappedSuperclass( annotatedClass ) ) {\n\t\t\t// @Entity and @MappedSuperclass on the same class leads to NPE down the road\n\t\t\tif ( isEntity( annotatedClass ) ) {\n\t\t\t\tthrow new AnnotationException( \"Type '\" + annotatedClass.getName()\n\t\t\t\t\t\t+ \"' is annotated both '@Entity' and '@MappedSuperclass'\" );\n\t\t\t}\n\t\t\tif ( annotatedClass.hasDirectAnnotationUsage( Table.class ) ) {\n\t\t\t\tthrow new AnnotationException( \"Mapped superclass '\" + annotatedClass.getName()\n\t\t\t\t\t\t+ \"' may not specify a '@Table'\" );\n\t\t\t}\n\t\t\tif ( annotatedClass.hasDirectAnnotationUsage( Inheritance.class ) ) {\n\t\t\t\tthrow new AnnotationException( \"Mapped superclass '\" + annotatedClass.getName()\n\t\t\t\t\t\t+ \"' may not specify an '@Inheritance' mapping strategy\" );\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static void bindTypeDescriptorRegistrations(\n\t\t\tAnnotationTarget annotatedElement,\n\t\t\tMetadataBuildingContext context) {\n\t\tfinal var managedBeanRegistry = context.getBootstrapContext().getManagedBeanRegistry();\n\t\tfinal var sourceModelContext = modelsContext( context );","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java#L269-L305","documentation":"The same type carries both '@Entity' and '@MappedSuperclass'. These are mutually exclusive roles: an entity is a mapped, instantiated persistent type, while a mapped superclass only contributes state/mapping to subclasses. Historically this combination produced a NullPointerException deep inside binding, so Hibernate now fails fast with this clear message.","triggerScenarios":"A class annotated '@Entity' (or otherwise processed as an entity) that also has a direct '@MappedSuperclass' annotation — often when someone converts an entity into a base class and leaves '@Entity' behind, or generates mappings that stamp both on.","commonSituations":"Refactoring an existing entity into a reusable superclass; annotation generators/processors emitting both; copy-paste of a template class that already had @MappedSuperclass.","solutions":["If the class should be a mapped superclass: remove '@Entity' (and any '@Table') so it only persists through subclasses.","If the class should be a concrete entity: remove '@MappedSuperclass' (its state will map to its own table).","For shared state across entities, keep '@MappedSuperclass' on an abstract base and put '@Entity' on each leaf."],"exampleFix":"// before\n@Entity            // both present\n@MappedSuperclass  // -> AnnotationException\npublic abstract class BaseEntity { @Id Long id; }\n\n// after\n@MappedSuperclass\npublic abstract class BaseEntity {\n    @Id @GeneratedValue\n    Long id;\n}\n\n@Entity\nclass Customer extends BaseEntity { String name; }","handlingStrategy":"validation","validationCode":"// Guard: a type may not be both @Entity and @MappedSuperclass\nif (cls.isAnnotationPresent(MappedSuperclass.class)\n        && cls.isAnnotationPresent(Entity.class)) {\n    throw new IllegalStateException(\n        cls.getName() + \" is annotated both @Entity and @MappedSuperclass\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Metadata md = sources.buildMetadata();\n} catch (AnnotationException e) {\n    // 'annotated both @Entity and @MappedSuperclass' -> keep exactly one role\n    throw newConfigurationException(\"Conflicting type-level annotations\", e);\n}","preventionTips":["Keep base classes '@MappedSuperclass' and abstract; entities stay leaf-level '@Entity'.","When promoting an entity to a base class, remove @Entity AND @Table in the same change.","Lint persistent classes in CI: reject types carrying both annotations."],"tags":["hibernate","jpa","mapped-superclass","entity-lifecycle","orm-mapping"],"backgroundTag":"mapped-superclass-misuse","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}