hibernate/hibernate-orm · error · ClassCastException

Cannot cast to entity type '{}'

Error message

Cannot cast to entity type '{}'

What it means

When a query argument is bound against an entity-typed parameter, QueryArguments special-cases Hibernate proxies (isInstance) but otherwise requires the value to be an instance of the entity's Java class. A value of any other class produces ClassCastException with the message 'Cannot cast to entity type <FQCN>'. This is Hibernate's entity-argument conversion path, not a bad cast in user code.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/query/internal/QueryArguments.java:119

	public static <T> T cast(Object value, JavaType<T> javaType) {
		if ( value == null ) {
			return null;
		}
		else if ( javaType instanceof EntityJavaType<?> ) {
			// special handling for entity arguments due to
			// the possibility of an uninitialized proxy
			// (which we don't want or need to fetch)
			if ( isInstance( value, javaType ) ) {
				// The proxy might not literally be an
				// instance of the entity class represented
				// by the unreified type T, but it is an
				// instance in spirit
				//noinspection unchecked
				return (T) value;
			}
			else {
				throw new ClassCastException( "Cannot cast to entity type '"
							+ javaType.getJavaTypeClass().getTypeName() + "'" );
			}
		}
		else {
			// require that the argument be assignable to the parameter
			return javaType.cast( javaType.coerce( value ) );
		}
	}
}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Pass an instance of the exact entity class the comparison expects.
  2. Compare by identifier instead: 'where o.customer.id = :cid' and bind customer.getId().
  3. When types are uncertain, inspect query.getParameterMetadata().getQueryParameter(name).getParameterType() before binding.

Example fix

// before
var q = session.createQuery("from Order o where o.customer = :c", Order.class);
q.setParameter("c", someVendor); // Vendor is not Customer -> ClassCastException

// after
q.setParameter("c", customer);
// or compare by id:
var q2 = session.createQuery("from Order o where o.customer.id = :cid", Order.class);
q2.setParameter("cid", customer.getId());
Defensive patterns

Strategy: type-guard

Validate before calling

static void bindEntity(org.hibernate.query.Query<?> q, String name, Object value, Class<?> entityJavaType) {
    Object unwrapped = org.hibernate.Hibernate.unproxy(value);
    if (unwrapped != null && !entityJavaType.isInstance(unwrapped))
        throw new IllegalArgumentException("Expected " + entityJavaType.getSimpleName()
            + " but got " + unwrapped.getClass().getSimpleName());
    q.setParameter(name, value);
}

Type guard

static boolean isEntityInstance(Object value, Class<?> entityJavaType) {
    return value == null || entityJavaType.isInstance(org.hibernate.Hibernate.unproxy(value));
}

Prevention

When it happens

Trigger: setParameter("c", value) on a query like "from Order o where o.customer = :c" where value is an instance of a different entity class (e.g. Vendor instead of Customer), or a DTO/Map passed where the mapped entity is expected.

Common situations: Similar domain classes or inheritance hierarchies where the wrong subtype flows through generic code; values arriving from generic Map<String,Object> request contexts; refactors that changed an entity type while callers still pass the old one.

Related errors


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