hibernate/hibernate-orm · error · UnknownEntityTypeException

{uee.getMessage()} ('{entityClass.getSimpleName()}' does not

Error message

{uee.getMessage()} ('{entityClass.getSimpleName()}' does not belong to this persistence unit|is not annotated '@Entity')

What it means

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).

Source

Thrown at hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java:1606

			// not given the opportunity to resolve a subclass entity name.
			// This allows the (we assume custom) interceptor the ability to
			// influence this decision if we were not able to based on the
			// given entityName
			try {
				return requireEntityPersister( entityName )
						.getSubclassEntityPersister( entity, getFactory() );
			}
			catch ( UnknownEntityTypeException uee ) {
				try {
					return getEntityPersister( null, entity );
				}
				catch ( HibernateException e ) {
					final var entityClass = entity.getClass();
					final String problem =
							entityClass.isAnnotationPresent( Entity.class )
									? "does not belong to this persistence unit"
									: "is not annotated '@Entity'";
					throw new UnknownEntityTypeException(
							uee.getMessage()
								+ " ('" + entityClass.getSimpleName() + "' " + problem + ")",
							e
					);
				}
			}
		}
	}

	// not for internal use:

	@Override
	@Nullable
	public Object getIdentifier(@Nonnull Object object) {
		checkOpen();
		checkTransactionSyncStatus();
		//noinspection ConstantValue
		if ( object == null ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Annotate the class with @Entity (jakarta.persistence.Entity) and give it an @Id — a missing id yields a different error later
  2. Add the class to the persistence unit: persistence.xml <class> entry, Spring Boot @EntityScan of its package, or Configuration.addAnnotatedClass()
  3. If multiple persistence units exist, perform the operation with the EntityManager/SessionFactory that actually maps the class
  4. Check the import: use jakarta.persistence.Entity (not javax) and ensure only one copy of the class is on the classpath/module path

Example fix

// before
public class CustomerDto { ... } // no @Entity
session.persist(customerDto); // UnknownEntityTypeException: not annotated '@Entity'

// after
@Entity
public class Customer {
    @Id @GeneratedValue
    private Long id;
    // ...
}
session.persist(customer);
Defensive patterns

Strategy: validation

Validate before calling

static boolean isManaged(SessionFactory sf, Class<?> clazz) {
    try {
        sf.getJpaMetamodel().entity(clazz);
        return true;
    } catch (IllegalArgumentException e) {
        return false; // not mapped in this persistence unit
    }
}

if (isManaged(sessionFactory, obj.getClass())) {
    session.persist(obj);
} else {
    throw new IllegalArgumentException("Not an entity of this persistence unit: " + obj.getClass());
}

Type guard

static Optional<EntityType<?>> asEntity(SessionFactory sf, Class<?> c) {
    try {
        return Optional.of(sf.getJpaMetamodel().entity(c));
    } catch (IllegalArgumentException e) {
        return Optional.empty();
    }
}

Try / catch

try {
    session.persist(obj);
} catch (UnknownEntityTypeException e) {
    throw new IllegalArgumentException(
        "Class '" + obj.getClass().getName()
            + "' is not mapped in this persistence unit "
            + "(missing @Entity or wrong persistence unit)", e);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/234ff28f83d60c7e. Report an issue: GitHub.