hibernate/hibernate-orm · error · MappingException

association must specify the referenced entity

Error message

association must specify the referenced entity

What it means

ToOne.isValid() validates every many-to-one/one-to-one style association before the SessionFactory completes. A ToOne must carry a referencedEntityName — the entity being pointed at. If it is null (no target class was resolvable at mapping time), validation aborts with this MappingException because Hibernate cannot build a joinable association to an unnamed target.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/mapping/ToOne.java:118

	public boolean isTypeSpecified() {
		return referencedEntityName!=null;
	}

	@Override
	public boolean isSame(SimpleValue other) {
		return other instanceof ToOne toOne && isSame( toOne );
	}

	public boolean isSame(ToOne other) {
		return super.isSame( other )
			&& Objects.equals( referencedPropertyName, other.referencedPropertyName )
			&& Objects.equals( referencedEntityName, other.referencedEntityName );
	}

	@Override
	public boolean isValid(MappingContext mappingContext) throws MappingException {
		if ( referencedEntityName==null ) {
			throw new MappingException("association must specify the referenced entity");
		}
		return super.isValid( mappingContext );
	}

	@Override
	public boolean isLazy() {
		return lazy;
	}

	@Override
	public void setLazy(boolean lazy) {
		this.lazy = lazy;
	}

	public boolean isUnwrapProxy() {
		return unwrapProxy;
	}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Specify the target explicitly: <many-to-one name="order" class="Order"/> or @ManyToOne(targetEntity = Order.class).
  2. Use a concrete, parameterized field type (private Order order; not private Object order;) so reflection infers the entity.
  3. In programmatic models, always call manyToOne.setReferencedEntityName("Order") before validation.
  4. Run metadata validation in a unit test to catch this at CI time.

Example fix

// before
@ManyToOne
private Object customer;

// after
@ManyToOne(targetEntity = Customer.class)
private Customer customer;
Defensive patterns

Strategy: type-guard

Validate before calling

// hbm.xml: statically check every <many-to-one>/<one-to-one> has class= before boot
// annotations: ensure fields are concrete entity types or carry targetEntity

Type guard

static boolean resolvesToEntity(Class<?> type) {
    return type != Object.class && !type.isPrimitive()
            && !Collection.class.isAssignableFrom(type)
            && type != Void.class; // crude guard — real check is the mapped-entity lookup
}

Try / catch

try {
    sf = cfg.buildSessionFactory();
} catch (MappingException e) {
    if ("association must specify the referenced entity".equals(e.getMessage())) {
        // find the association missing class=/targetEntity — message lacks the name, so check XMLEntityResolver errors or mapping debug logs
    }
    throw e;
}

Prevention

When it happens

Trigger: hbm.xml <many-to-one name="x"/> with neither class nor target-entity attribute; annotation @ManyToOne on a raw, unparameterized field (Object, untyped generic) with no targetEntity; programmatic mapping forgetting to call setReferencedEntityName; a @OneToOne mapped by generic/wildcard types where reflection cannot infer the target.

Common situations: Hand-edited hbm.xml dropping the class attribute; entities using raw types (Map instead of Map<Order,...>) so reflection fails; programmatic boot-model builders assembled in code; copying association mappings and forgetting to adjust the target; Kotlin/Scala generic fields that erase before Hibernate reads them.

Related errors


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