{"record":{"id":"234ff28f83d60c7e","repo":"hibernate/hibernate-orm","slug":"uee-getmessage-entityclass-getsimplename","errorCode":null,"errorMessage":"{uee.getMessage()} ('{entityClass.getSimpleName()}' does not belong to this persistence unit|is not annotated '@Entity')","messagePattern":"(.+?) \\('(.+?)' does not belong to this persistence unit\\|is not annotated '@Entity'\\)","errorType":"exception","errorClass":"UnknownEntityTypeException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java","lineNumber":1606,"sourceCode":"\t\t\t// not given the opportunity to resolve a subclass entity name.\n\t\t\t// This allows the (we assume custom) interceptor the ability to\n\t\t\t// influence this decision if we were not able to based on the\n\t\t\t// given entityName\n\t\t\ttry {\n\t\t\t\treturn requireEntityPersister( entityName )\n\t\t\t\t\t\t.getSubclassEntityPersister( entity, getFactory() );\n\t\t\t}\n\t\t\tcatch ( UnknownEntityTypeException uee ) {\n\t\t\t\ttry {\n\t\t\t\t\treturn getEntityPersister( null, entity );\n\t\t\t\t}\n\t\t\t\tcatch ( HibernateException e ) {\n\t\t\t\t\tfinal var entityClass = entity.getClass();\n\t\t\t\t\tfinal String problem =\n\t\t\t\t\t\t\tentityClass.isAnnotationPresent( Entity.class )\n\t\t\t\t\t\t\t\t\t? \"does not belong to this persistence unit\"\n\t\t\t\t\t\t\t\t\t: \"is not annotated '@Entity'\";\n\t\t\t\t\tthrow new UnknownEntityTypeException(\n\t\t\t\t\t\t\tuee.getMessage()\n\t\t\t\t\t\t\t\t+ \" ('\" + entityClass.getSimpleName() + \"' \" + problem + \")\",\n\t\t\t\t\t\t\te\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// not for internal use:\n\n\t@Override\n\t@Nullable\n\tpublic Object getIdentifier(@Nonnull Object object) {\n\t\tcheckOpen();\n\t\tcheckTransactionSyncStatus();\n\t\t//noinspection ConstantValue\n\t\tif ( object == null ) {","sourceCodeStart":1588,"sourceCodeEnd":1624,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java#L1588-L1624","documentation":"When SessionImpl.getEntityPersister cannot resolve an entity class, it retries and finally rethrows UnknownEntityTypeException with a diagnostic hint: the class either is not annotated @Entity or is not part of this persistence unit. The class-level check ('does not belong to this persistence unit' vs 'is not annotated') distinguishes a missing annotation from a class mapped elsewhere (different persistence unit or classloader).","triggerScenarios":"Passing an object to session operations (persist, merge, lock, refresh) whose class is not mapped in the factory that owns the session: a DTO or value class, a class annotated only with @Embeddable/MappedSuperclass, or an @Entity that lives in a different persistence unit. Also classloader splits in application servers serving two copies of the class.","commonSituations":"Mixing DTOs and entities and accidentally persisting a DTO; multiple persistence units (orders vs users) and an entity saved via the wrong EMF; Spring entity scanning missing a package (@EntityScan too narrow); JPMS/WildFly module classloader differences making the same class name loaded twice; jakarta vs javax @Entity import mixing after migration.","solutions":["Annotate the class with @Entity (jakarta.persistence.Entity) and give it an @Id — a missing id yields a different error later","Add the class to the persistence unit: persistence.xml <class> entry, Spring Boot @EntityScan of its package, or Configuration.addAnnotatedClass()","If multiple persistence units exist, perform the operation with the EntityManager/SessionFactory that actually maps the class","Check the import: use jakarta.persistence.Entity (not javax) and ensure only one copy of the class is on the classpath/module path"],"exampleFix":"// before\npublic class CustomerDto { ... } // no @Entity\nsession.persist(customerDto); // UnknownEntityTypeException: not annotated '@Entity'\n\n// after\n@Entity\npublic class Customer {\n    @Id @GeneratedValue\n    private Long id;\n    // ...\n}\nsession.persist(customer);","handlingStrategy":"validation","validationCode":"static boolean isManaged(SessionFactory sf, Class<?> clazz) {\n    try {\n        sf.getJpaMetamodel().entity(clazz);\n        return true;\n    } catch (IllegalArgumentException e) {\n        return false; // not mapped in this persistence unit\n    }\n}\n\nif (isManaged(sessionFactory, obj.getClass())) {\n    session.persist(obj);\n} else {\n    throw new IllegalArgumentException(\"Not an entity of this persistence unit: \" + obj.getClass());\n}","typeGuard":"static Optional<EntityType<?>> asEntity(SessionFactory sf, Class<?> c) {\n    try {\n        return Optional.of(sf.getJpaMetamodel().entity(c));\n    } catch (IllegalArgumentException e) {\n        return Optional.empty();\n    }\n}","tryCatchPattern":"try {\n    session.persist(obj);\n} catch (UnknownEntityTypeException e) {\n    throw new IllegalArgumentException(\n        \"Class '\" + obj.getClass().getName()\n            + \"' is not mapped in this persistence unit \"\n            + \"(missing @Entity or wrong persistence unit)\", e);\n}","preventionTips":["Keep DTO and entity packages separate so unmapped types never reach session operations","With multiple persistence units, route by entity package to the matching EntityManagerFactory","Verify Spring @EntityScan / persistence.xml <class> entries cover every entity package","After jakarta migration, remove javax.persistence leftovers so @Entity annotations resolve consistently"],"tags":["hibernate","entity-mapping","persistence-unit","unknown-entity","annotation","classloader"],"backgroundTag":"entity-not-in-persistence-unit","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}