I think we should revisit the idea of having the interfaces IdentityObject/ValueObject.
They serve two purposes 1/ documentation: explain the difference between an identity class and a value class 2/ type restriction: can be used as type or bound of type parameter for algorithms that only works with identity class Sadly, our design as evolved but not those interfaces, they do not work well as type restriction, because the type is lost once an interface/j.l.Object is used and the cost of their introduction is higher than previously though. 1/ documentation - Those interface split the possible types in two groups but the spec split the types in 3, B1/B2/B3, thus they are not aligned anymore with the new design. - they will be noise in the future, for Valhalla, the separation between identity object and value object may be important but from a POV of someone learning/discovering the language it's a corner case (like primitives are). This is even more true with the introduction of B2, you can use B2 for a long time without knowing what a value type is. So having such interfaces front and center is too much. 2/ as type - Being a value class or a primitive class is a runtime behavior not a compile time behavior, so representing them with special types (a type is a compile time construct) will always be an approximation. As a consequence, you can have an identity class (resp value class) typed with a type which is not a subtype of IdentityObject (resp ValueObject). This discrepancy is hard to grasp for beginners (in fact not only for beginners) and make IdentityObject/ValueObject useless because if a method takes an IdentityObject as parameter but the type is an interface, users will have to cast it into an IdentityObject which defeat the purpose of having such interface. (This is the reason why ObjectOutputStream.writeObject() takes an Object as parameter and not Serializable) And the cost of introduction is high - they are not source backward compatible class A {} class B {} var list = List.of(new A(), new B()); List<Object> list2 = list; - they are not binary backward compatible new Object().getClass() != Object.class - at least IdentityObject needs to be injected at runtime, which by side effect requires patching several VM components: reflection/j.l.invoke, JVMTI, etc making the VM spec more complex that it should be. You may not agree with some of my points, nevertheless, the current design is not aligned with the B1/B2/B3 world, have a high cost and with little benefit so i think it's time to remove those interfaces from the design. regards, Rémi