Plain Java serialisation writes out and reads back the above test classes without any problems.
Digging around XStream code, the culprit turned out to be this line in the ExternalizableConverter.unmarshal():
final Externalizable externalizable = (Externalizable) type.newInstance();
Digging further into Java serialisation code, I found out that they instantiate externalizable objects slightly differently. They obtain an instance of the default Constructor, then they remove access protection from it, and only then they call newInstance() on the constructor object. For reference, please see java.io.ObjectStreamClass.getExternalizableConstructor() private method.
I have created a modified version of an ExternalizableConverter, that follows the Java serialisation way of constructing objects, and it worked flawlessly in the end. Please see the attachment.