hibernate/hibernate-orm · error · MappingException

optimistic-lock=all|dirty not supported for joined-subclass

Error message

optimistic-lock=all|dirty not supported for joined-subclass mappings [{entityName}]

What it means

JoinedSubclassEntityPersister rejects OptimisticLockType.ALL/DIRTY at boot with MappingException('optimistic-lock=all|dirty not supported for joined-subclass mappings'). In JOINED inheritance the entity's columns span several tables, so a single UPDATE cannot compare all/dirty columns in its WHERE clause; version-based optimistic locking is the only supported style, and @DynamicUpdate does not change this.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java:215

					discriminatorValue = new DiscriminatorValue.Literal( persistentClass.getSubclassId() );
					discriminatorSQLString = Integer.toString( persistentClass.getSubclassId() );
				}
				catch ( Exception e ) {
					throw new MappingException( "Could not format discriminator value to SQL string", e );
				}
			}
		}
		else {
			explicitDiscriminatorColumnName = null;
			discriminatorAlias = IMPLICIT_DISCRIMINATOR_ALIAS;
			discriminatorType = basicTypeRegistry.resolve( StandardBasicTypes.INTEGER );
			discriminatorValue = null;
			discriminatorSQLString = null;
			forceDiscriminator = false;
		}

		if ( optimisticLockStyle().isAllOrDirty() ) {
			throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" );
		}

		//MULTITABLES

		final int idColumnSpan = getIdentifierColumnSpan();

		final ArrayList<String> tableNames = new ArrayList<>();
		final ArrayList<String[]> keyColumns = new ArrayList<>();
//		final ArrayList<String[]> keyColumnReaders = new ArrayList<>();
//		final ArrayList<String[]> keyColumnReaderTemplates = new ArrayList<>();
		final ArrayList<Boolean> cascadeDeletes = new ArrayList<>();
		final var tableClosure = persistentClass.getTableClosure();
		final var keyClosure = persistentClass.getKeyClosure();
		for ( int i = 0; i < tableClosure.size() && i < keyClosure.size(); i++ ) {
			tableNames.add( determineTableName( tableClosure.get(i) ) );

			final var key = keyClosure.get(i);
			final String[] keyCols = new String[idColumnSpan];

View on GitHub (pinned to fad1729dce)

Solutions

  1. Use @Version-based locking on JOINED hierarchies (remove @OptimisticLock — VERSION is the default)
  2. If all/dirty locking is mandatory, switch the hierarchy to SINGLE_TABLE where it is supported
  3. Keep @DynamicUpdate only for SQL trimming; it never enables all/dirty locking on JOINED mappings

Example fix

// before
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DynamicUpdate
@OptimisticLock(type = OptimisticLockType.DIRTY)
public abstract class Account { ... }

// after
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Account {
    @Version private long version; // version-based optimistic locking
}
Defensive patterns

Strategy: validation

Validate before calling

Inheritance inh = root.getAnnotation(Inheritance.class);
OptimisticLock lock = root.getAnnotation(OptimisticLock.class);
if ( inh != null && inh.strategy() == InheritanceType.JOINED && lock != null
        && (lock.type() == OptimisticLockType.ALL
         || lock.type() == OptimisticLockType.DIRTY) ) {
    throw new IllegalStateException(
        root.getName() + ": optimistic-lock ALL/DIRTY is unsupported with JOINED inheritance");
}

Try / catch

try {
    SessionFactory sf = metadata.getSessionFactoryBuilder().build();
}
catch ( org.hibernate.MappingException e ) {
    throw new IllegalStateException("SessionFactory boot failed: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: @Inheritance(strategy = JOINED) root annotated @OptimisticLock(type = ALL or DIRTY) (or hbm.xml optimistic-lock="all|dirty") — fails during SessionFactory boot even when @DynamicUpdate is present.

Common situations: Switching an inheritance hierarchy from SINGLE_TABLE to JOINED while keeping the lock style; copying optimistic-lock configuration across hierarchy roots; porting legacy mappings that relied on all/dirty locking.

Related errors


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