hibernate/hibernate-orm · error · MappingException

all @TenantId fields must have the same type: <parameterType

Error message

all @TenantId fields must have the same type: <parameterTypeName> differs from <tenantIdTypeName>

What it means

Hibernate implements @TenantId as one shared filter definition whose parameter type is fixed by the first @TenantId attribute bound. For every subsequent entity, TenantIdBinder compares the filter parameter's Java type with that entity's @TenantId property type; any difference (String vs Long, String vs UUID, etc.) throws a MappingException naming both types at metadata build time.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/binder/internal/TenantIdBinder.java:68

			collector.addFilterDefinition(
					new FilterDefinition(
							FILTER_NAME,
							"",
							false,
							true,
							singletonMap( PARAMETER_NAME, tenantIdType ),
							emptyMap()
					)
			);
		}
		else {
			final var tenantIdTypeJtd = tenantIdType.getJavaTypeDescriptor();
			final var jdbcMapping = filterDefinition.getParameterJdbcMapping( PARAMETER_NAME );
			assert jdbcMapping != null;
			final var parameterJavaType = jdbcMapping.getJavaTypeDescriptor();
			if ( !parameterJavaType.getJavaTypeClass()
					.equals( tenantIdTypeJtd.getJavaTypeClass() ) ) {
				throw new MappingException(
						"all @TenantId fields must have the same type: "
								+ parameterJavaType.getTypeName()
								+ " differs from "
								+ tenantIdTypeJtd.getTypeName()
				);
			}
		}
		persistentClass.addFilter(
				FILTER_NAME,
				columnNameOrFormula( property )
						+ " = :"
						+ PARAMETER_NAME,
				true,
				emptyMap(),
				emptyMap()
		);

		if ( isRowLevelSecurityEnabled( buildingContext ) ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Pick one tenant id Java type (String, UUID, Long, ...) and use it for every @TenantId attribute in the whole domain.
  2. Where DB column types differ, unify them with a schema migration rather than mixing Java types.
  3. If types truly must differ per table, @TenantId cannot be used — switch to explicit @FilterDef/@Filter with per-entity conditions.

Example fix

// before
@Entity public class Customer { @TenantId String tenantId; ... }
@Entity public class Order    { @TenantId Long tenantId; ... }

// after
@Entity public class Customer { @TenantId String tenantId; ... }
@Entity public class Order    { @TenantId String tenantId; ... }
Defensive patterns

Strategy: validation

Validate before calling

Set<Class<?>> tenantIdTypes = new HashSet<>();
for (Class<?> cls : entityClasses) {
    for (Field f : cls.getDeclaredFields()) {
        if (f.isAnnotationPresent(org.hibernate.annotations.TenantId.class)) {
            tenantIdTypes.add(f.getType());
        }
    }
}
if (tenantIdTypes.size() > 1) {
    throw new IllegalStateException("Conflicting @TenantId types: " + tenantIdTypes);
}

Try / catch

Catch org.hibernate.MappingException during SessionFactory build; the message names both conflicting types. Fix the mapping — no runtime recovery exists.

Prevention

When it happens

Trigger: Two or more entities declare @TenantId with different Java types — e.g. @TenantId String tenantId on Customer and @TenantId Long tenantId on Order — and SessionFactory bootstrap binds the tenant filter for the later entity and detects the mismatch.

Common situations: Incrementally adding @TenantId to new entities using a different id type than existing ones; mixed legacy schemas (BIGINT tenant keys in some tables, VARCHAR in others); a half-finished migration from numeric tenant codes to UUIDs.

Related errors


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