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
- Pick one tenant id Java type (String, UUID, Long, ...) and use it for every @TenantId attribute in the whole domain.
- Where DB column types differ, unify them with a schema migration rather than mixing Java types.
- 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
- Standardize one tenant id Java type across the whole domain before adopting @TenantId.
- Add a build-time check that all @TenantId fields share the same type.
- Complete tenant-id type migrations in one release, not incrementally per entity.
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
- @TenantId attribute must be mapped to a single column or for
- Class '<componentClassName>' is an '@Embeddable' type and ma
- Property '<propertyName>' may not be annotated '@BatchSize'
- One to many association '<propertyName>' was annotated '@Col
- Collection '<propertyName>' was annotated '@Collate'
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/c136daf937f48510.
Report an issue: GitHub.