If a member of a class is a value type T and mapped as a component, NHibernate will always detect objects with a value of default(T) as dirty.
The problem is in ComponentType.IsDirty(): the original value as ready by NHibernate will be null, whereas the value returned from an instance will be a boxed default(T). The current logic does not treat null as equivalent to default(T) for value types, which it should do.
It is possible in the constructor of ComponentType to box a default(T) and use this instead of null in the IsDirty() methods - this works as expected.
public override bool IsDirty( object x, object y, ISessionImplementor session )
if( x == y )
// In ComponentType() the object componentClassDefault is
// set to a new instance of componentClass iff componentClass is a value type.
if (x == null && y.Equals(componentClassDefault) ||
y == null && x.Equals(componentClassDefault))
if( x == null || y == null )