hibernate/hibernate-orm · error · PersistenceException

Hibernate cannot unwrap EntityManagerFactory as '{type.getNa

Error message

Hibernate cannot unwrap EntityManagerFactory as '{type.getName()}'

What it means

JPA's EntityManagerFactory.unwrap(Class) must succeed for implementor classes and the JPA interfaces, and throw PersistenceException otherwise. Hibernate supports unwrapping to SessionFactory/SessionFactoryImplementor, EntityManagerFactory, the JpaMetamodel/MappingMetamodel, and the QueryEngine; anything else (e.g. javax.persistence.EntityManagerFactory variants of another provider, DataSource, custom classes) reaches the terminal PersistenceException.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java:1265

		}

		if ( type.isInstance( runtimeMetamodels ) ) {
			return type.cast( runtimeMetamodels );
		}

		if ( type.isInstance( runtimeMetamodels.getJpaMetamodel() ) ) {
			return type.cast( runtimeMetamodels.getJpaMetamodel() );
		}

		if ( type.isInstance( runtimeMetamodels.getMappingMetamodel() ) ) {
			return type.cast( runtimeMetamodels.getMappingMetamodel() );
		}

		if ( type.isInstance( queryEngine ) ) {
			return type.cast( queryEngine );
		}

		throw new PersistenceException( "Hibernate cannot unwrap EntityManagerFactory as '" + type.getName() + "'" );
	}

	@Override
	public void runInTransaction(@Nonnull Consumer<EntityManager> work) {
		inTransaction( work );
	}

	@Override
	public <H extends EntityHandler> void runInTransaction(
			@Nonnull Class<H> handlerType, @Nonnull Consumer<H> consumer) {
		if ( EntityManager.class.isAssignableFrom( handlerType ) ) {
			//noinspection unchecked
			inTransaction( (Consumer<EntityManager>) consumer );
		}
		else if ( EntityAgent.class.isAssignableFrom( handlerType ) ) {
			//noinspection unchecked
			inStatelessTransaction( (Consumer<EntityAgent>) consumer );
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Unwrap the EntityManager (not the factory) to get Session/SessionImplementor: em.unwrap(Session.class)
  2. Use only documented targets on the factory: SessionFactory.class, SessionFactoryImplementor.class, Metamodel/JpaMetamodel, MappingMetamodel, QueryEngine, EntityManagerFactory.class
  3. To reach the DataSource, unwrap the ServiceRegistry instead: sf.getServiceRegistry().requireService(ConnectionProvider.class)
  4. After jakarta migration, make sure you pass the jakarta.persistence classes, not javax.persistence leftovers

Example fix

// before
Session session = emf.unwrap(Session.class); // PersistenceException: cannot unwrap

// after
Session session = entityManager.unwrap(Session.class);
// or, for factory-level needs:
SessionFactoryImplementor sfi = emf.unwrap(SessionFactoryImplementor.class);
Defensive patterns

Strategy: type-guard

Validate before calling

static final Set<Class<?>> FACTORY_UNWRAP_TARGETS = Set.of(
        EntityManagerFactory.class, SessionFactory.class,
        SessionFactoryImplementor.class, Metamodel.class);

if (FACTORY_UNWRAP_TARGETS.contains(type)) {
    return emf.unwrap(type);
}

Type guard

static boolean factoryUnwrappable(Class<?> t) {
    return EntityManagerFactory.class.equals(t)
            || SessionFactory.class.equals(t)
            || SessionFactoryImplementor.class.equals(t)
            || Metamodel.class.isAssignableFrom(t)
            || t.getName().startsWith("org.hibernate.engine.query.spi.QueryEngine");
}

Try / catch

try {
    SessionFactory sf = emf.unwrap(SessionFactory.class);
} catch (PersistenceException e) {
    // type not supported by Hibernate's factory unwrap — use a dedicated accessor instead
    throw new UnsupportedOperationException("Cannot unwrap EMF to " + type, e);
}

Prevention

When it happens

Trigger: Calling emf.unwrap(SomeClass.class) with a type outside Hibernate's supported set — e.g. unwrap(DataSource.class), unwrap(Session.class) (sessions come from EntityManager.unwrap, not the factory), or a class from a different JPA provider. Each branch in unwrap() does type.isInstance(...) and the final else throws.

Common situations: Copy-pasted unwrap(Session.class) or unwrap(Connection.class) code intended for EntityManager; portability layers that unwrap to provider-specific classes; using the older javax vs jakarta EntityManagerFactory class object after a Jakarta migration.

Related errors


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