hibernate/hibernate-orm · error · UnsupportedOperationException

Derived root does not have an entity type. Use getReferenced

Error message

Derived root does not have an entity type. Use getReferencedPathSource() instead.

What it means

SqmDerivedRoot is the root created for HQL "from (select ...) alias" (derived table in the from clause). Its rows come from an inner subquery, so the JPA Root contract getModel() cannot return an EntityType and Hibernate throws UnsupportedOperationException (the source even carries a comment debating whether to throw - it does). getReferencedPathSource() exposes the subquery's select-shape instead.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/sqm/tree/spi/domain/SqmDerivedRoot.java:94

	@Nonnull
	@Override
	public SqmSubQuery<T> getQueryPart() {
		return subQuery;
	}

	@Override
	public <X> X accept(SemanticQueryWalker<X> walker) {
		return walker.visitRootDerived( this );
	}

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// JPA

	@Nonnull
	@Override
	public SqmEntityDomainType<T> getModel() {
		// Or should we throw an exception instead?
		throw new UnsupportedOperationException( "Derived root does not have an entity type. Use getReferencedPathSource() instead." );
	}

	@Override
	public String getEntityName() {
		throw new UnsupportedOperationException( "Derived root does not have an entity type. Use getReferencedPathSource() instead." );
	}

	@Override
	public SqmPathSource<T> getResolvedModel() {
		return getReferencedPathSource();
	}

	@Override
	@Nonnull
	public SqmCorrelatedRoot<T> createCorrelation() {
		return new SqmCorrelatedDerivedRoot<>( this );
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Call getReferencedPathSource() (or getResolvedModel()) to inspect the derived row type.
  2. Type-guard generic code: skip getModel() for SqmDerivedRoot and SqmCteRoot instances.
  3. Select from the mapped entity directly when EntityType-driven features (locking, caching, metamodel queries) are needed.
  4. Where feasible, move the derived projection into a subquery in the where clause so the outer query keeps entity roots.

Example fix

// before - derived root has no entity model
EntityType<?> et = (EntityType<?>) derivedRoot.getModel();

// after - use the referenced path source of the derived table
SqmPathSource<?> shape = derivedRoot.getReferencedPathSource();
Class<?> rowType = shape.getJavaType();
Defensive patterns

Strategy: type-guard

Validate before calling

static boolean hasEntityType(jakarta.persistence.criteria.Root<?> root) {
    return !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmDerivedRoot)
        && !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmCteRoot)
        && !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmFunctionRoot)
        && !(root instanceof org.hibernate.query.sqm.tree.spi.domain.SqmCorrelatedDerivedRoot);
}

Type guard

static boolean isDerivedRoot(Object node) {
    return node instanceof org.hibernate.query.sqm.tree.spi.domain.SqmDerivedRoot;
}

Try / catch

try {
    EntityType<?> et = (EntityType<?>) root.getModel();
} catch (UnsupportedOperationException e) {
    SqmPathSource<?> shape = ((SqmDerivedRoot<?>) root).getReferencedPathSource();
    Class<?> rowType = shape.getJavaType();
}

Prevention

When it happens

Trigger: HQL "select d.x from (select e.id as x from Employee e) d" combined with Java code that calls root.getModel() on the derived root; criteria/metamodel frameworks resolving an EntityType from every root; correlating the derived root (createCorrelation()) and calling getModel() on the resulting SqmCorrelatedDerivedRoot.

Common situations: Reporting queries refactored to derived tables for paging/deduplication while generic root code still expects entities; Hibernate 6.6+/7 making "from (subquery)" a supported pattern that now flows into previously entity-only code paths; migration from Blaze-Persistence or native SQL subselect-from queries.

Related errors


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