You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/03/02 07:17:11 UTC

[isis] 03/11: ISIS-2553: using LogicalType instead of ObjectSpedId (1st iteration)

This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 0fe22fba57ef0a840dfb237b5259665b1a5efbfc
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Mar 1 17:14:39 2021 +0100

    ISIS-2553: using LogicalType instead of ObjectSpedId (1st iteration)
---
 .../java/org/apache/isis/applib/Identifier.java    | 26 +++++----
 .../org/apache/isis/applib/id/HasLogicalType.java  | 15 ++---
 .../id/{TypeIdentifier.java => LogicalType.java}   | 30 +++++-----
 .../org/apache/isis/applib/id}/ObjectSpecId.java   | 10 ++--
 .../isis/applib/services/bookmark/Bookmark.java    | 35 +++++++-----
 .../org/apache/isis/applib/IdentifierTests.java    | 10 ++--
 .../isis/applib/events/InteractionEventTest.java   |  4 +-
 .../apache/isis/applib/id/TypeIdentifierTest.java  |  4 +-
 .../isis/core/metamodel/adapter/oid/Oid.java       | 33 ++++++-----
 .../core/metamodel/adapter/oid/Oid_Marshaller.java |  6 +-
 .../isis/core/metamodel/adapter/oid/Oid_Root.java  | 55 ++++++-------------
 .../isis/core/metamodel/adapter/oid/Oid_Value.java |  3 +-
 .../isis/core/metamodel/adapter/oid/RootOid.java   |  2 +-
 .../isis/core/metamodel/facetapi/FeatureType.java  | 18 +++---
 .../isis/core/metamodel/facets/FacetedMethod.java  |  4 +-
 .../metamodel/facets/FacetedMethodParameter.java   |  4 +-
 .../ViewModelSemanticCheckingFacetFactory.java     | 10 ++--
 .../DomainObjectAnnotationFacetFactory.java        |  6 +-
 .../mixin/MetaModelValidatorForMixinTypes.java     |  6 +-
 .../object/objectspecid/ObjectSpecIdFacet.java     |  2 +-
 .../objectspecid/ObjectSpecIdFacetAbstract.java    |  2 +-
 .../ObjectSpecIdFacetOnStandaloneList.java         |  2 +-
 .../identify/ObjectIdentifier_builtinHandlers.java |  8 +--
 .../services/appfeat/ApplicationFeatureId.java     |  5 +-
 .../metamodel/MetaModelServiceDefault.java         |  7 +--
 .../title/TitlesAndTranslationsValidator.java      | 10 ++--
 .../isis/core/metamodel/spec/ManagedObjects.java   |  3 +-
 .../core/metamodel/spec/ObjectSpecification.java   | 13 ++++-
 ...ClassResolver.java => LogicalTypeResolver.java} |  6 +-
 ...efault.java => LogicalTypeResolverDefault.java} | 14 ++---
 .../metamodel/specloader/SpecificationLoader.java  | 49 ++++++++++++-----
 .../specloader/SpecificationLoaderDefault.java     | 33 +++++------
 .../specloader/specimpl/ObjectActionMixedIn.java   |  4 +-
 .../specimpl/ObjectSpecificationAbstract.java      | 15 +++--
 .../specimpl/OneToManyAssociationMixedIn.java      |  4 +-
 .../specimpl/OneToOneAssociationMixedIn.java       |  4 +-
 .../specimpl/dflt/ObjectSpecificationDefault.java  |  2 +-
 .../adapter/oid/LogicalTypeTestFactory.java        | 21 ++++---
 .../adapter/oid/OidMarshallerTest_marshall.java    |  4 +-
 .../oid/OidMarshallerTest_roundtripping.java       |  6 +-
 .../adapter/oid/OidMarshallerTest_unmarshal.java   |  8 +--
 .../core/metamodel/adapter/oid/OidVersionTest.java | 18 +++---
 ...dDefaultTest_valueSemantics_whenPersistent.java | 14 ++---
 .../metamodel/adapter/oid/RootOidTest_create.java  |  9 ++-
 .../facetapi/FeatureTypeTest_identifierFor.java    |  6 +-
 .../facets/AbstractFacetFactoryJUnit4TestCase.java |  4 +-
 .../metamodel/facets/AbstractFacetFactoryTest.java |  4 +-
 ...nEventHelperTest_newActionInteractionEvent.java |  8 +--
 ...HelperTest_newCollectionDomainEvent_forAdd.java |  8 +--
 ...perTest_newCollectionDomainEvent_forRemove.java |  8 +--
 ...HelperTest_newPropertyDomainEvent_forClear.java |  6 +-
 ...elperTest_newPropertyDomainEvent_forModify.java |  6 +-
 .../DomainObjectAnnotationFacetFactoryTest.java    |  2 +-
 .../ObjectTypeAnnotationFacetFactoryTest.java      |  2 +-
 .../facets/object/mixin/MixinIntendedAs.java       |  4 +-
 ...SpecIdFacetDerivedFromClassNameFactoryTest.java |  2 +-
 .../metamodel/id/TypeIdentifierTestFactory.java    |  6 +-
 .../spec/ObjectSpecIdTest_constructor.java         |  2 +
 .../spec/ObjectSpecIdTest_valueSemantics.java      |  1 +
 .../specloader/SpecificationCacheDefaultTest.java  | 18 +++---
 .../testspec/ObjectSpecificationStub.java          | 24 ++++----
 .../isis/core/runtime/memento/ObjectMemento.java   | 18 +++---
 .../runtime/memento/ObjectMementoCollection.java   |  7 ++-
 .../runtime/memento/ObjectMementoForEmpty.java     | 10 ++--
 .../core/runtime/memento/ObjectMementoService.java |  6 +-
 .../bookmarks/BookmarkServiceDefault.java          |  3 +-
 .../command/CommandExecutorServiceDefault.java     |  2 +-
 .../AbstractRoleAndPermissionsFixtureScript.java   |  2 +-
 .../component/FullCalendarWithEventHandling.java   |  2 +-
 .../metamodel/facets/entity/JdoEntityFacet.java    |  2 +-
 .../object/query/VisitorForClauseAbstract.java     |  7 +--
 .../facets/object/query/VisitorForFromClause.java  |  7 +--
 .../object/query/VisitorForVariablesClause.java    |  7 +--
 ...JdoDiscriminatorAnnotationFacetFactoryTest.java |  2 +-
 .../object/version/TypeIdentifierTestFactory.java  |  6 +-
 .../testing/AbstractFacetFactoryTest.java          |  4 +-
 .../testdomain/domainmodel/SpecLoaderTest.java     |  6 +-
 .../shiro/authorization/AuthorizorShiro.java       |  2 +-
 .../security/shiro/TypeIdentifierTestFactory.java  | 10 ++--
 .../common/model/mementos/ActionMemento.java       |  4 +-
 .../common/model/menu/MenuUiModelProvider.java     |  2 +-
 .../domainobjects/DomainObjectReprRenderer.java    |  9 ++-
 .../rendering/domainobjects/JsonValueEncoder.java  |  2 +-
 .../JsonValueEncoderTest_appendValueAndFormat.java |  2 +-
 .../JsonValueEncoderTest_asAdapter.java            |  2 +-
 .../JsonValueEncoderTest_asObject.java             |  2 +-
 .../resources/DomainObjectResourceServerside.java  |  7 +--
 .../resources/DomainTypeResourceServerside.java    | 21 ++++---
 .../viewer/wicket/model/links/LinkAndLabel.java    |  8 +--
 .../wicket/model/mementos/CollectionMemento.java   |  8 +--
 .../wicket/model/mementos/PropertyMemento.java     | 36 ++++++------
 .../model/models/BookmarkTreeNodeComparator.java   |  4 +-
 .../wicket/model/models/ManagedObjectModel.java    | 10 ++--
 .../wicket/model/models/PageParameterUtil.java     |  2 +-
 .../viewer/wicket/model/models/ScalarModel.java    |  7 ++-
 .../model/models/ScalarModelWithMultiPending.java  |  9 ++-
 .../bookmarkedpages/BookmarkedPagesPanel.java      |  5 +-
 .../scalars/ScalarPanelSelectAbstract.java         |  4 +-
 .../ui/components/widgets/select2/ChoiceExt.java   |  8 +--
 .../ui/components/widgets/select2/Select2.java     |  6 +-
 .../widgets/select2/Select2ChoiceExt.java          | 16 +++---
 .../widgets/select2/Select2MultiChoiceExt.java     | 15 ++---
 .../ObjectAdapterMementoProviderAbstract.java      |  6 +-
 ...tAdapterMementoProviderForValueChoicesTest.java | 20 ++++---
 .../integration/ConverterForObjectAdapter.java     |  3 +-
 .../mementos/ObjectMementoServiceWicket.java       | 22 ++++----
 .../viewer/services/mementos/ObjectMementoWkt.java | 64 +++++++++++-----------
 107 files changed, 543 insertions(+), 519 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/Identifier.java b/api/applib/src/main/java/org/apache/isis/applib/Identifier.java
index 7253d89..bd287be 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/Identifier.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/Identifier.java
@@ -23,7 +23,8 @@ import java.io.Serializable;
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.HasLogicalType;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
@@ -33,18 +34,19 @@ import lombok.NonNull;
 import lombok.val;
 
 /**
- * Combines {@link TypeIdentifier} and member identification (from properties, collections or actions),
+ * Combines {@link LogicalType} and member identification (from properties, collections or actions),
  * to a fully qualified <i>feature</i> identifier.
  * <p> 
  * For {@link Identifier}(s) of type {@link Identifier.Type#CLASS} member information is 
  * left empty.   
  *  
  * @since 1.x revised for 2.0 {@index}
- * @see TypeIdentifier
+ * @see LogicalType
  */
 public class Identifier 
 implements 
     Comparable<Identifier>,
+    HasLogicalType,
     Serializable {
 
     private static final long serialVersionUID = 1L;
@@ -61,26 +63,26 @@ implements
 
     // -- FACTORY METHODS
 
-    public static Identifier classIdentifier(final TypeIdentifier typeIdentifier) {
+    public static Identifier classIdentifier(final LogicalType typeIdentifier) {
         return new Identifier(typeIdentifier, "", Can.empty(), Type.CLASS);
     }
 
     public static Identifier propertyOrCollectionIdentifier(
-            final TypeIdentifier typeIdentifier,
+            final LogicalType typeIdentifier,
             final String propertyOrCollectionName) {
         return new Identifier(typeIdentifier, propertyOrCollectionName, Can.empty(), 
                 Type.PROPERTY_OR_COLLECTION);
     }
 
     public static Identifier actionIdentifier(
-            final TypeIdentifier typeIdentifier,
+            final LogicalType typeIdentifier,
             final String actionName, 
             final Class<?>... parameterClasses) {
         return actionIdentifier(typeIdentifier, actionName, classNamesOf(parameterClasses));
     }
 
     public static Identifier actionIdentifier(
-            final TypeIdentifier typeIdentifier,
+            final LogicalType typeIdentifier,
             final String actionName, 
             final Can<String> parameterClassNames) {
         return new Identifier(typeIdentifier, actionName, parameterClassNames, Type.ACTION);
@@ -88,7 +90,7 @@ implements
 
     // -- INSTANCE FIELDS
 
-    @Getter private final TypeIdentifier typeIdentifier;
+    @Getter(onMethod_ = {@Override}) private final LogicalType logicalType;
     
     @Getter private final String className;
     
@@ -117,13 +119,13 @@ implements
     // -- CONSTRUCTOR
 
     private Identifier(
-            final TypeIdentifier typeIdentifier,
+            final LogicalType logicalType,
             final String memberName, 
             final Can<String> memberParameterClassNames, 
             final Type type) {
         
-        this.typeIdentifier = typeIdentifier;
-        this.className = typeIdentifier.getClassName();
+        this.logicalType = logicalType;
+        this.className = logicalType.getClassName();
         this.memberName = memberName;
         this.memberParameterClassNames = memberParameterClassNames;
         this.type = type;
@@ -144,7 +146,7 @@ implements
     // -- LOGICAL ID
     
     public String getLogicalIdentityString(final @NonNull String delimiter) {
-        return typeIdentifier.getLogicalTypeName() 
+        return getLogicalTypeName() 
                 + delimiter 
                 + memberNameAndParameterClassNamesIdentityString;
     }
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/TypeIdentifierTestFactory.java b/api/applib/src/main/java/org/apache/isis/applib/id/HasLogicalType.java
similarity index 74%
copy from persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/TypeIdentifierTestFactory.java
copy to api/applib/src/main/java/org/apache/isis/applib/id/HasLogicalType.java
index 22a3868..5e0523a 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/TypeIdentifierTestFactory.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/id/HasLogicalType.java
@@ -16,16 +16,17 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.persistence.jdo.metamodel.facets.object.version;
+package org.apache.isis.applib.id;
 
-import org.apache.isis.applib.id.TypeIdentifier;
-
-final class TypeIdentifierTestFactory {
+/**
+ * @since 2.0 {@index}
+ */
+public interface HasLogicalType {
 
-    private static class Customer {};
+    LogicalType getLogicalType();
     
-    static TypeIdentifier customer() {
-        return TypeIdentifier.fqcn(Customer.class);
+    default String getLogicalTypeName() {
+        return getLogicalType().getLogicalTypeName();
     }
     
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/id/TypeIdentifier.java b/api/applib/src/main/java/org/apache/isis/applib/id/LogicalType.java
similarity index 90%
rename from api/applib/src/main/java/org/apache/isis/applib/id/TypeIdentifier.java
rename to api/applib/src/main/java/org/apache/isis/applib/id/LogicalType.java
index a925402..360f1e8 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/id/TypeIdentifier.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/id/LogicalType.java
@@ -41,9 +41,9 @@ import lombok.val;
  * @since 2.0 {@index}
  */
 @ToString
-public final class TypeIdentifier 
+public final class LogicalType 
 implements 
-    Comparable<TypeIdentifier>,
+    Comparable<LogicalType>,
     Serializable {
     
     private static final long serialVersionUID = 1L;
@@ -66,29 +66,29 @@ implements
      * Returns a new TypeIdentifier based on the corresponding class
      * and a {@code logicalNameProvider} for lazy logical name lookup.  
      */
-    public static TypeIdentifier lazy(
+    public static LogicalType lazy(
             final @NonNull Class<?> correspondingClass, 
             final @NonNull Supplier<String> logicalNameProvider) {
         
-        return new TypeIdentifier(correspondingClass, logicalNameProvider);
+        return new LogicalType(correspondingClass, logicalNameProvider);
     }
     
     /**
      * Returns a new TypeIdentifier based on the corresponding class
      * and (ahead of time) known {@code logicalName}. 
      */
-    public static TypeIdentifier eager(
+    public static LogicalType eager(
             final @NonNull Class<?> correspondingClass, 
             final String logicalName) {
         
-        return new TypeIdentifier(correspondingClass, logicalName);
+        return new LogicalType(correspondingClass, logicalName);
     }
     
     /**
      * Use the corresponding class's fully qualified name for the {@code logicalName}. 
      * Most likely used in testing scenarios.
      */
-    public static TypeIdentifier fqcn(
+    public static LogicalType fqcn(
             final @NonNull Class<?> correspondingClass) {
         
         return eager(correspondingClass, correspondingClass.getName());
@@ -96,7 +96,7 @@ implements
     
     // -- HIDDEN CONSTRUTORS
     
-    private TypeIdentifier(
+    private LogicalType(
             final @NonNull Class<?> correspondingClass, 
             final @NonNull Supplier<String> logicalNameProvider) {
         
@@ -104,7 +104,7 @@ implements
         this.logicalNameProvider = logicalNameProvider;
     }
     
-    private TypeIdentifier(
+    private LogicalType(
             final @NonNull Class<?> correspondingClass, 
             final String logicalName) {
         
@@ -185,13 +185,13 @@ implements
         if (this == obj) {
             return true;
         }
-        if (obj instanceof TypeIdentifier) {
-            return isEqualTo((TypeIdentifier) obj);
+        if (obj instanceof LogicalType) {
+            return isEqualTo((LogicalType) obj);
         }
         return false;
     }
     
-    public boolean isEqualTo(final @Nullable TypeIdentifier other) {
+    public boolean isEqualTo(final @Nullable LogicalType other) {
         if(other==null) {
             return false;
         }
@@ -204,7 +204,7 @@ implements
     }
 
     @Override
-    public int compareTo(final @Nullable TypeIdentifier other) {
+    public int compareTo(final @Nullable LogicalType other) {
         val otherClassName = other!=null
                 ? other.getCorrespondingClass().getCanonicalName()
                 : null;
@@ -226,13 +226,13 @@ implements
         private final @NonNull Class<?> correspondingClass;
         private final @NonNull String logicalTypeName;
         
-        private SerializationProxy(TypeIdentifier typeIdentifier) {
+        private SerializationProxy(LogicalType typeIdentifier) {
             this.correspondingClass = typeIdentifier.getCorrespondingClass();
             this.logicalTypeName = typeIdentifier.getLogicalTypeName();
         }
 
         private Object readResolve() {
-            return TypeIdentifier.eager(correspondingClass, logicalTypeName);
+            return LogicalType.eager(correspondingClass, logicalTypeName);
         }
     }
     
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecId.java b/api/applib/src/main/java/org/apache/isis/applib/id/ObjectSpecId.java
similarity index 84%
rename from core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecId.java
rename to api/applib/src/main/java/org/apache/isis/applib/id/ObjectSpecId.java
index d64ffce..ba9d81b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecId.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/id/ObjectSpecId.java
@@ -16,13 +16,11 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.core.metamodel.spec;
+package org.apache.isis.applib.id;
 
 import java.io.Serializable;
 
-import org.apache.isis.applib.id.TypeIdentifier;
 import org.apache.isis.commons.internal.base._Refs;
-import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 
 import static org.apache.isis.commons.internal.base._With.requiresNotEmpty;
 
@@ -32,12 +30,12 @@ import lombok.RequiredArgsConstructor;
 import lombok.Value;
 
 /**
- * Represents an {@link ObjectSpecification}, as determined by
- * an {@link ObjectSpecIdFacet}.
+ * Represents an {@link org.apache.isis.core.metamodel.spec.ObjectSpecification}, as determined by
+ * an {@link org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet}.
  *
  * <p>
  * Has value semantics.
- * @deprecated use {@link TypeIdentifier} instead
+ * @deprecated use {@link LogicalType} instead
  */
 @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
 @Value
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
index 6c87837..f26a757 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
@@ -44,27 +44,23 @@ import lombok.val;
 @lombok.Value @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
 public class Bookmark implements Serializable {
 
-    private static final long serialVersionUID = 2L;
+    private static final long serialVersionUID = 3L;
 
     protected static final String SEPARATOR = ":";
 
     /**
-     * corresponds directly to the object's specification-id
+     * Corresponds directly to the object's logical-type-name (aka. object-type).
      * @see RootOid
      */
-    @NonNull  private final String objectType;
+    @NonNull  private final String logicalTypeName;
     @NonNull  private final String identifier;
 
     @Nullable private final String hintId;
 
-    public static Bookmark of(String objectType, String identifier) {
-
-        return new Bookmark(objectType, identifier, /*hintId*/ null);
-
-        // ...
+    public static Bookmark of(String logicalTypeName, String identifier) {
+        return new Bookmark(logicalTypeName, identifier, /*hintId*/ null);
     }
 
-
     /**
      * Round-trip with {@link #toString()} representation.
      */
@@ -88,7 +84,7 @@ public class Bookmark implements Serializable {
 
     public OidDto toOidDto() {
         val oidDto = new OidDto();
-        oidDto.setType(getObjectType());
+        oidDto.setType(getLogicalTypeName());
         oidDto.setId(getIdentifier());
         return oidDto;
     }
@@ -99,23 +95,32 @@ public class Bookmark implements Serializable {
     
     /**
      * The canonical form of the {@link Bookmark}, that is 
-     * &quot;{@link #getObjectType() objectType}{@value #SEPARATOR}{@link #getIdentifier()}&quot;.
+     * &quot;{@link #getLogicalTypeName() logical-type-name}{@value #SEPARATOR}{@link #getIdentifier()}&quot;.
      *
      * <p>
      * This is parseable by the {@link #parse(String)}.
      */
     @Override
     public String toString() {
-        return objectType + SEPARATOR + identifier;
+        return toStringUsingIdentifier(identifier);
     }
 
-
     public Bookmark withHintId(@NonNull String hintId) {
-        return new Bookmark(this.getObjectType(), this.getIdentifier(), hintId); 
+        return new Bookmark(this.getLogicalTypeName(), this.getIdentifier(), hintId); 
     }
 
     public String toStringUsingIdentifier(String id) {
-        return objectType + SEPARATOR + id;
+        return logicalTypeName + SEPARATOR + id;
     }
+    
+    // -- DEPRECATIONS 
+    
+    /**
+     * @deprecated use {@link #getLogicalTypeName()} instead
+     */
+    public String getObjectType() {
+        return getLogicalTypeName();
+    }
+    
 
 }
diff --git a/api/applib/src/test/java/org/apache/isis/applib/IdentifierTests.java b/api/applib/src/test/java/org/apache/isis/applib/IdentifierTests.java
index 810c6d4..4a52aaa 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/IdentifierTests.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/IdentifierTests.java
@@ -29,7 +29,7 @@ import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 
 public class IdentifierTests {
@@ -42,7 +42,7 @@ public class IdentifierTests {
 
     @Test
     public void canInstantiateClassIdentifier() {
-        identifier = Identifier.classIdentifier(TypeIdentifier.fqcn(SomeDomainClass.class));
+        identifier = Identifier.classIdentifier(LogicalType.fqcn(SomeDomainClass.class));
         assertThat(identifier, is(not(nullValue())));
     }
 
@@ -50,21 +50,21 @@ public class IdentifierTests {
     public void classIdentifierClassNameIsSet() {
         final Class<?> domainClass = SomeDomainClass.class;
         final String domainClassFullyQualifiedName = domainClass.getCanonicalName();
-        identifier = Identifier.classIdentifier(TypeIdentifier.fqcn(domainClass));
+        identifier = Identifier.classIdentifier(LogicalType.fqcn(domainClass));
         assertThat(identifier.getClassName(), is(domainClassFullyQualifiedName));
     }
 
     @Test
     public void memberParameterNames() {
         final Class<?> domainClass = SomeDomainClass.class;
-        identifier = Identifier.actionIdentifier(TypeIdentifier.fqcn(domainClass), "placeOrder", int.class, String.class);
+        identifier = Identifier.actionIdentifier(LogicalType.fqcn(domainClass), "placeOrder", int.class, String.class);
         assertThat(identifier.getMemberParameterClassNames(), is(Can.of("int", "java.lang.String")));
     }
 
     @Test
     public void paramsIdentityString() {
         final Class<?> domainClass = SomeDomainClass.class;
-        identifier = Identifier.actionIdentifier(TypeIdentifier.fqcn(domainClass), "placeOrder", int.class, String.class, BigDecimal.class);
+        identifier = Identifier.actionIdentifier(LogicalType.fqcn(domainClass), "placeOrder", int.class, String.class, BigDecimal.class);
         assertThat(
                 identifier.getFullIdentityString(), 
                 is("org.apache.isis.applib.SomeDomainClass#placeOrder(int,java.lang.String,java.math.BigDecimal)"));
diff --git a/api/applib/src/test/java/org/apache/isis/applib/events/InteractionEventTest.java b/api/applib/src/test/java/org/apache/isis/applib/events/InteractionEventTest.java
index 1604ed1..8e70ad2 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/events/InteractionEventTest.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/events/InteractionEventTest.java
@@ -30,7 +30,7 @@ import static org.junit.Assert.assertEquals;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.wrapper.events.InteractionEvent;
 
 public class InteractionEventTest {
@@ -51,7 +51,7 @@ public class InteractionEventTest {
     public void setUp() {
         source = new Object();
         identifier = Identifier.actionIdentifier(
-                TypeIdentifier.fqcn(CustomerOrder.class), 
+                LogicalType.fqcn(CustomerOrder.class), 
                 "cancelOrder", new Class[] { String.class, boolean.class });
         advisorClass = this.getClass();
     }
diff --git a/api/applib/src/test/java/org/apache/isis/applib/id/TypeIdentifierTest.java b/api/applib/src/test/java/org/apache/isis/applib/id/TypeIdentifierTest.java
index 9f6b344..6698d61 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/id/TypeIdentifierTest.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/id/TypeIdentifierTest.java
@@ -37,7 +37,7 @@ class TypeIdentifierTest {
     @Test
     void eager() {
         
-        val original = TypeIdentifier.fqcn(SomeDomainClass.class);
+        val original = LogicalType.fqcn(SomeDomainClass.class);
         
         _SerializationTester.assertEqualsOnRoundtrip(original);
         
@@ -53,7 +53,7 @@ class TypeIdentifierTest {
     @Test
     void lazy() {
         
-        val original = TypeIdentifier.lazy(SomeDomainClass.class, ()->"hello");
+        val original = LogicalType.lazy(SomeDomainClass.class, ()->"hello");
         
         _SerializationTester.assertEqualsOnRoundtrip(original);
         
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
index 7738c67..c884b4e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid.java
@@ -22,8 +22,8 @@ package org.apache.isis.core.metamodel.adapter.oid;
 import java.io.Serializable;
 
 import org.apache.isis.applib.annotation.Value;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.schema.common.v2.OidDto;
 
 /**
@@ -46,19 +46,16 @@ public interface Oid extends Serializable {
     }
     
     /**
-     * {@link ObjectSpecId} of the domain object this instance is representing, or when parented,
-     * the ObjectSpecId of the parent domain object. When representing a value returns {@code null}.   
+     * The logical-type-name of the domain object this instance is representing.
+     * When representing a value returns {@code null}.
      */
-    ObjectSpecId getObjectSpecId();
+    String getLogicalTypeName();
 
     // -- MARSHALLING
 
     public static interface Marshaller {
-
         String marshal(RootOid rootOid);
-
-        String joinAsOid(String domainType, String instanceId);
-
+        String joinAsOid(String logicalTypeName, String instanceId);
     }
 
     public static Marshaller marshaller() {
@@ -68,11 +65,8 @@ public interface Oid extends Serializable {
     // -- UN-MARSHALLING
 
     public static interface Unmarshaller {
-
         <T extends Oid> T unmarshal(String oidStr, Class<T> requestedType);
-
         String splitInstanceId(String oidStr);
-
     }
 
     public static Unmarshaller unmarshaller() {
@@ -90,18 +84,27 @@ public interface Oid extends Serializable {
 
         public static RootOid ofBookmark(final Bookmark bookmark) {
             return Oid_Root.of(
-                    ObjectSpecId.of(bookmark.getObjectType()), 
+                    bookmark.getLogicalTypeName(), 
                     bookmark.getIdentifier());
         }
         
         public static RootOid ofDto(final OidDto oid) {
             return Oid_Root.of(
-                    ObjectSpecId.of(oid.getType()), 
+                    oid.getType(), 
                     oid.getId());
         }
 
-        public static RootOid root(final ObjectSpecId objectSpecId, final String identifier) {
-            return Oid_Root.of(objectSpecId, identifier);
+        public static RootOid root(final LogicalType logicalType, final String identifier) {
+            return Oid_Root.of(
+                    logicalType.getLogicalTypeName(), 
+                    identifier);
+        }
+        
+        @Deprecated
+        public static RootOid root(final String logicalTypeName, final String identifier) {
+            return Oid_Root.of(
+                    logicalTypeName, 
+                    identifier);
         }
         
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Marshaller.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Marshaller.java
index 3ce264d..1e0a10e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Marshaller.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Marshaller.java
@@ -20,7 +20,6 @@ package org.apache.isis.core.metamodel.adapter.oid;
 
 import java.util.Iterator;
 import java.util.List;
-import java.util.Objects;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
@@ -30,7 +29,6 @@ import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 import static org.apache.isis.commons.internal.base._Strings.splitThenStream;
 
@@ -176,7 +174,7 @@ final class Oid_Marshaller implements Oid.Marshaller, Oid.Unmarshaller {
             if(aggregateOidParts.isEmpty()) {
                 ensureCorrectType(oidStr, requestedType, RootOid.class);
                 return _Casts.uncheckedCast(
-                        Oid_Root.of(ObjectSpecId.of(rootObjectType), rootIdentifier));
+                        Oid_Root.of(rootObjectType, rootIdentifier));
             } else {
                 throw _Exceptions.illegalArgument("Aggregated OIDs are no longer supported");
             }
@@ -224,7 +222,7 @@ final class Oid_Marshaller implements Oid.Marshaller, Oid.Unmarshaller {
     @Override
     public final String marshal(RootOid rootOid) {
         _Assert.assertFalse(rootOid.isValue(), "cannot marshal values");
-        return rootOid.getObjectSpecId() + SEPARATOR + rootOid.getIdentifier();
+        return rootOid.getLogicalTypeName() + SEPARATOR + rootOid.getIdentifier();
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
index 6d338e5..f81ad21 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
@@ -23,40 +23,39 @@ import java.util.Objects;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.internal.codec._UrlDecoderUtil;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.schema.common.v2.OidDto;
 
-import static org.apache.isis.commons.internal.base._With.requires;
-
+import lombok.Getter;
+import lombok.NonNull;
 import lombok.val;
 
 final class Oid_Root implements RootOid {
 
     private static final long serialVersionUID = 3L;
 
-    private final ObjectSpecId objectSpecId;
-    private final String identifier;
+    @Getter(onMethod_ = {@Override}) private final String logicalTypeName;
+    @Getter(onMethod_ = {@Override}) private final String identifier;
+    
     private final int hashCode;
 
     public static Oid_Root of(
-            ObjectSpecId objectSpecId, 
-            String identifier) {
-
-        return new Oid_Root(objectSpecId, identifier);
+            final @NonNull String logicalTypeName, 
+            final @NonNull String identifier) {
+        return new Oid_Root(logicalTypeName, identifier);
     }
 
-    private Oid_Root(ObjectSpecId objectSpecId, String identifier) {
+    private Oid_Root(
+            final String logicalTypeName, 
+            final String identifier) {
 
-        requires(objectSpecId, "objectSpecId");
-        requires(identifier, "identifier");
-
-        this.objectSpecId = objectSpecId;
+        this.logicalTypeName = logicalTypeName;
         this.identifier = identifier;
         this.hashCode = calculateHash();
 
     }
 
-    // -- deString'able, enString
+    // -- ENCODING 
+    
     public static Oid_Root deStringEncoded(final String urlEncodedOidStr) {
         final String oidStr = _UrlDecoderUtil.urlDecode(urlEncodedOidStr);
         return deString(oidStr);
@@ -71,36 +70,19 @@ final class Oid_Root implements RootOid {
         return Oid.marshaller().marshal(this);
     }
 
-    // -- Properties
-    @Override
-    public ObjectSpecId getObjectSpecId() {
-        return objectSpecId;
-    }
-
-    @Override
-    public String getIdentifier() {
-        return identifier;
-    }
-
     @Override
     public Bookmark asBookmark() {
-        val objectType = getObjectSpecId().asString();
-        val identifier = getIdentifier();
-        return Bookmark.of(objectType, identifier);
+        return Bookmark.of(logicalTypeName, getIdentifier());
     }
 
     @Override
     public OidDto asOidDto() {
-
         val oidDto = new OidDto();
-
-        oidDto.setType(getObjectSpecId().asString());
+        oidDto.setType(logicalTypeName);
         oidDto.setId(getIdentifier());
-
         return oidDto;
     }
 
-
     @Override
     public boolean equals(final Object other) {
         if (other == null) {
@@ -116,7 +98,7 @@ final class Oid_Root implements RootOid {
     }
 
     public boolean equals(final Oid_Root other) {
-        return Objects.equals(objectSpecId, other.getObjectSpecId()) 
+        return Objects.equals(logicalTypeName, other.getLogicalTypeName()) 
                 && Objects.equals(identifier, other.getIdentifier());
     }
 
@@ -133,8 +115,7 @@ final class Oid_Root implements RootOid {
     // -- HELPER
 
     private int calculateHash() {
-        return Objects.hash(objectSpecId, identifier);
+        return Objects.hash(logicalTypeName, identifier);
     }
 
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Value.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Value.java
index ed116a5..7b620ff 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Value.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Value.java
@@ -20,7 +20,6 @@
 package org.apache.isis.core.metamodel.adapter.oid;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.schema.common.v2.OidDto;
 
 final class Oid_Value implements RootOid {
@@ -40,7 +39,7 @@ final class Oid_Value implements RootOid {
     }
 
     @Override
-    public ObjectSpecId getObjectSpecId() {
+    public String getLogicalTypeName() {
         return null;
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
index 7ce0b30..2128207 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
@@ -53,7 +53,7 @@ public interface RootOid extends Oid {
     default public ManagedObject loadObject(SpecificationLoader specificationLoader) {
         val mmc = ((SpecificationLoaderDefault)specificationLoader).getMetaModelContext();
 
-        val spec = specificationLoader.loadSpecification(this.getObjectSpecId());
+        val spec = specificationLoader.loadSpecification(this.getLogicalTypeName());
         val objectId = this.getIdentifier();
 
         val objectLoadRequest = ObjectLoader.Request.of(spec, objectId);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FeatureType.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FeatureType.java
index 6ffc8af..1c3e27d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FeatureType.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facetapi/FeatureType.java
@@ -23,7 +23,7 @@ import java.beans.Introspector;
 import java.lang.reflect.Method;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.core.metamodel.commons.StringExtensions;
 import org.apache.isis.core.metamodel.facets.FacetFactory;
@@ -43,25 +43,25 @@ public enum FeatureType {
          * The supplied method can be null; at any rate it will be ignored.
          */
         @Override
-        public Identifier identifierFor(final TypeIdentifier typeIdentifier, final Method method) {
+        public Identifier identifierFor(final LogicalType typeIdentifier, final Method method) {
             return Identifier.classIdentifier(typeIdentifier);
         }
     },
     PROPERTY("Property") {
         @Override
-        public Identifier identifierFor(final TypeIdentifier typeIdentifier, final Method method) {
+        public Identifier identifierFor(final LogicalType typeIdentifier, final Method method) {
             return propertyOrCollectionIdentifierFor(typeIdentifier, method);
         }
     },
     COLLECTION("Collection") {
         @Override
-        public Identifier identifierFor(final TypeIdentifier typeIdentifier, final Method method) {
+        public Identifier identifierFor(final LogicalType typeIdentifier, final Method method) {
             return propertyOrCollectionIdentifierFor(typeIdentifier, method);
         }
     },
     ACTION("Action") {
         @Override
-        public Identifier identifierFor(final TypeIdentifier typeIdentifier, final Method method) {
+        public Identifier identifierFor(final LogicalType typeIdentifier, final Method method) {
             final String fullMethodName = method.getName();
             final Class<?>[] parameterTypes = method.getParameterTypes();
             return Identifier.actionIdentifier(typeIdentifier, fullMethodName, parameterTypes);
@@ -72,7 +72,7 @@ public enum FeatureType {
          * Always returns <tt>null</tt>.
          */
         @Override
-        public Identifier identifierFor(final TypeIdentifier typeIdentifier, final Method method) {
+        public Identifier identifierFor(final LogicalType typeIdentifier, final Method method) {
             return null;
         }
     },
@@ -81,7 +81,7 @@ public enum FeatureType {
          * Always returns <tt>null</tt>.
          */
         @Override
-        public Identifier identifierFor(final TypeIdentifier typeIdentifier, final Method method) {
+        public Identifier identifierFor(final LogicalType typeIdentifier, final Method method) {
             return null;
         }
     };
@@ -121,7 +121,7 @@ public enum FeatureType {
     }
 
     private static Identifier propertyOrCollectionIdentifierFor(
-            final TypeIdentifier typeIdentifier, 
+            final LogicalType typeIdentifier, 
             final Method method) {
         
         final String capitalizedName = StringExtensions.asJavaBaseName(method.getName());
@@ -152,7 +152,7 @@ public enum FeatureType {
         return isProperty() || isCollection();
     }
 
-    public abstract Identifier identifierFor(TypeIdentifier typeIdentifier, Method method);
+    public abstract Identifier identifierFor(LogicalType typeIdentifier, Method method);
 
     @Override
     public String toString() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethod.java
index 9bc6cb6..4de5a69 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethod.java
@@ -25,7 +25,7 @@ import java.util.Collections;
 import java.util.List;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.internal.collections._Collections;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.commons.StringExtensions;
@@ -169,7 +169,7 @@ public class FacetedMethod extends TypedHolderDefault implements IdentifiedHolde
         this.owningType = declaringType;
         this.method = method;
         
-        val typeIdentifier = TypeIdentifier.lazy(
+        val typeIdentifier = LogicalType.lazy(
                 declaringType,
                 ()->getSpecificationLoader().loadSpecification(declaringType).getSpecId().asString());
         
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethodParameter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethodParameter.java
index ac7a0d8..1f3f15d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethodParameter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetedMethodParameter.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.metamodel.facets;
 import java.lang.reflect.Method;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.IdentifiedHolder;
 
@@ -41,7 +41,7 @@ implements IdentifiedHolder {
         
         super(featureType, type);
         
-        val typeIdentifier = TypeIdentifier.lazy(
+        val typeIdentifier = LogicalType.lazy(
                 declaringType,
                 ()->getSpecificationLoader().loadSpecification(declaringType).getSpecId().asString());
         
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
index 664c3de..8640de7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
@@ -24,7 +24,7 @@ import org.apache.isis.applib.RecreatableDomainObject;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainObjectLayout;
 import org.apache.isis.applib.annotation.Nature;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
@@ -76,7 +76,7 @@ implements MetaModelRefiner {
         if(implementsViewModel && implementsRecreatableDomainObject) {
             validator.onFailure(
                     facetHolder,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                    Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     "Inconsistent view model / domain object semantics; %s should not implement "
                     + "both %s and %s interfaces (implement one or the other)",
                     cls.getName(),
@@ -87,7 +87,7 @@ implements MetaModelRefiner {
         if(implementsViewModel && annotatedWithDomainObject) {
             validator.onFailure(
                     facetHolder,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                    Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     "Inconsistent view model / domain object semantics; %1$s should not implement "
                     + "%2$s and be annotated with @%3$s (annotate with %4$s instead of %2$s, or implement %5s instead of %2$s)",
                     cls.getName(),
@@ -100,7 +100,7 @@ implements MetaModelRefiner {
         if(implementsViewModel && annotatedWithDomainObjectLayout) {
             validator.onFailure(
                     facetHolder,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                    Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     "Inconsistent view model / domain object semantics; %1$s should not implement "
                     + "%2$s and be annotated with @%3$s (annotate with @%4$s instead of %3$s, or implement %5$s instead of %2$s)",
                     cls.getName(),
@@ -115,7 +115,7 @@ implements MetaModelRefiner {
                 && implementsRecreatableDomainObject) {
             validator.onFailure(
                     facetHolder,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                    Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     "Inconsistent view model / domain object semantics; %1$s should not be annotated with "
                     + "@%2$s with nature of %3$s and also implement %4$s (specify a nature of %5$s)",
                     cls.getName(),
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index 6467369..f43439e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -39,7 +39,8 @@ import org.apache.isis.applib.events.lifecycle.ObjectPersistingEvent;
 import org.apache.isis.applib.events.lifecycle.ObjectRemovingEvent;
 import org.apache.isis.applib.events.lifecycle.ObjectUpdatedEvent;
 import org.apache.isis.applib.events.lifecycle.ObjectUpdatingEvent;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.commons.having.HasUniqueId;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.collections._Multimaps;
@@ -74,7 +75,6 @@ import org.apache.isis.core.metamodel.facets.object.mixin.MetaModelValidatorForM
 import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacetForDomainObjectAnnotation;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForValidationFailures;
@@ -221,7 +221,7 @@ implements MetaModelRefiner, PostConstructMethodCache, ObjectSpecIdFacetFactory
         }
         autoCompleteMethodInvalid.onFailure(
                 facetHolder,
-                Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                Identifier.classIdentifier(LogicalType.fqcn(cls)),
                 "%s annotation on %s specifies method '%s' that does not exist in repository '%s'",
                 annotationName, cls.getName(), methodName, repositoryClass.getName());
         return null;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
index 5d27005..34ee847 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MetaModelValidatorForMixinTypes.java
@@ -19,7 +19,7 @@
 package org.apache.isis.core.metamodel.facets.object.mixin;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.internal.reflection._Reflect;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForValidationFailures;
@@ -52,14 +52,14 @@ public class MetaModelValidatorForMixinTypes extends MetaModelValidatorForValida
         if(mixinContructors.getCardinality().isZero()) {
             onFailure(
                     facetHolder,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(candidateMixinType)),
+                    Identifier.classIdentifier(LogicalType.fqcn(candidateMixinType)),
                     "%s: annotated with %s annotation but does not have a public 1-arg constructor",
                     candidateMixinType.getName(), 
                     annotation);
         } else {
             onFailure(
                     facetHolder,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(candidateMixinType)),
+                    Identifier.classIdentifier(LogicalType.fqcn(candidateMixinType)),
                     "%s: annotated with %s annotation needs a single public 1-arg constructor but has %d",
                     candidateMixinType.getName(), 
                     annotation,
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacet.java
index 18c5174..cd559d8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacet.java
@@ -19,8 +19,8 @@
 package org.apache.isis.core.metamodel.facets.object.objectspecid;
 
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.facetapi.Facet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 
 /**
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetAbstract.java
index acd36a3..ad86b0d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetAbstract.java
@@ -21,10 +21,10 @@ package org.apache.isis.core.metamodel.facets.object.objectspecid;
 
 import java.util.Map;
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 public abstract class ObjectSpecIdFacetAbstract extends
 FacetAbstract implements ObjectSpecIdFacet {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetOnStandaloneList.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetOnStandaloneList.java
index 680eec9..e57718b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetOnStandaloneList.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetOnStandaloneList.java
@@ -19,9 +19,9 @@
 
 package org.apache.isis.core.metamodel.facets.object.objectspecid.classname;
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacetAbstract;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 public class ObjectSpecIdFacetOnStandaloneList extends ObjectSpecIdFacetAbstract {
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java
index efa7aa9..b7a2be5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectIdentifier_builtinHandlers.java
@@ -61,7 +61,7 @@ class ObjectIdentifier_builtinHandlers {
         @Override
         public RootOid handle(ManagedObject managedObject) {
             final String identifier = SERVICE_IDENTIFIER;
-            return Oid.Factory.root(managedObject.getSpecification().getSpecId(), identifier);
+            return Oid.Factory.root(managedObject.getSpecification().getLogicalType(), identifier);
         }
 
     }
@@ -87,7 +87,7 @@ class ObjectIdentifier_builtinHandlers {
                 throw _Exceptions.unrecoverable(msg);
             }
             val identifier = entityFacet.identifierFor(spec, pojo);
-            return Oid.Factory.root(spec.getSpecId(), identifier);
+            return Oid.Factory.root(spec.getLogicalType(), identifier);
         }
 
     }
@@ -118,7 +118,7 @@ class ObjectIdentifier_builtinHandlers {
             val spec = managedObject.getSpecification();
             val recreatableObjectFacet = spec.getFacet(ViewModelFacet.class);
             val identifier = recreatableObjectFacet.memento(managedObject.getPojo());
-            return Oid.Factory.root(spec.getSpecId(), identifier);
+            return Oid.Factory.root(spec.getLogicalType(), identifier);
         }
 
     }
@@ -134,7 +134,7 @@ class ObjectIdentifier_builtinHandlers {
         public RootOid handle(ManagedObject managedObject) {
             val spec = managedObject.getSpecification();
             val identifier = UUID.randomUUID().toString();
-            return Oid.Factory.root(spec.getSpecId(), identifier);
+            return Oid.Factory.root(spec.getLogicalType(), identifier);
         }
 
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java
index 7ebd562..ba3ce09 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/appfeat/ApplicationFeatureId.java
@@ -33,7 +33,7 @@ import static java.util.Comparator.nullsFirst;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.annotation.Value;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.applib.services.appfeat.ApplicationMemberType;
 import org.apache.isis.applib.util.Equality;
 import org.apache.isis.applib.util.Hashing;
@@ -42,7 +42,6 @@ import org.apache.isis.applib.util.TitleBuffer;
 import org.apache.isis.applib.util.ToString;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 import lombok.NonNull;
 import lombok.val;
@@ -73,7 +72,7 @@ implements
 
     public static ApplicationFeatureId fromIdentifier(final @NonNull Identifier identifier) {
         
-        val logicalTypeName = identifier.getTypeIdentifier().getLogicalTypeName();
+        val logicalTypeName = identifier.getLogicalTypeName();
         
         if(identifier.getType().isClass()) {
             return newClass(logicalTypeName); 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
index b94e53e..13826b0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
@@ -30,6 +30,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.commanddto.processor.CommandDtoProcessor;
 import org.apache.isis.applib.services.grid.GridService;
@@ -43,7 +44,6 @@ import org.apache.isis.core.metamodel.facets.members.publish.command.CommandPubl
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureId;
 import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureType;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -70,8 +70,7 @@ public class MetaModelServiceDefault implements MetaModelService {
         if(objectType == null) {
             return null;
         }
-        final ObjectSpecId objectSpecId = ObjectSpecId.of(objectType);
-        final ObjectSpecification objectSpecification = specificationLoader.lookupBySpecIdElseLoad(objectSpecId);
+        final ObjectSpecification objectSpecification = specificationLoader.lookupBySpecIdElseLoad(objectType);
         return objectSpecification != null? objectSpecification.getCorrespondingClass(): null;
     }
 
@@ -221,7 +220,7 @@ public class MetaModelServiceDefault implements MetaModelService {
             return null;
         }
 
-        final ObjectSpecification spec = specificationLoader.lookupBySpecIdElseLoad(objectSpecId);
+        final ObjectSpecification spec = specificationLoader.lookupBySpecIdElseLoad(objectSpecId.asString());
         if(spec == null) {
             return null;
         }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java
index ccc0c93..52557cd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/title/TitlesAndTranslationsValidator.java
@@ -19,7 +19,7 @@
 package org.apache.isis.core.metamodel.services.title;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.title.TitleService;
 import org.apache.isis.commons.internal.base._Blackhole;
@@ -64,7 +64,7 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
             if(domainService == null) {
                 
                 val deficiencyOrigin = Identifier.classIdentifier(
-                        TypeIdentifier.eager(managedBeanAdapter.getBeanClass(), objectType));
+                        LogicalType.eager(managedBeanAdapter.getBeanClass(), objectType));
                 val facetHolder = specificationLoader.loadSpecification(managedBeanAdapter.getBeanClass());
                 
                 super.onFailure(
@@ -85,7 +85,7 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
                 e.printStackTrace();
                 
                 val deficiencyOrigin = Identifier.classIdentifier(
-                        TypeIdentifier.eager(managedBeanAdapter.getBeanClass(), objectType));
+                        LogicalType.eager(managedBeanAdapter.getBeanClass(), objectType));
                 val facetHolder = specificationLoader.loadSpecification(managedBeanAdapter.getBeanClass());
 
                 super.onFailure(
@@ -122,7 +122,7 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
                     } catch (Exception e) {
 
                         val deficiencyOrigin = Identifier.classIdentifier(
-                                TypeIdentifier.eager(correspondingClass, objSpec.getSpecId().asString()));
+                                LogicalType.eager(correspondingClass, objSpec.getSpecId().asString()));
                         val facetHolder = objSpec;
 
                         super.onFailure(
@@ -157,7 +157,7 @@ public class TitlesAndTranslationsValidator extends MetaModelValidatorAbstract {
 
                 val facetHolder = specificationLoader.loadSpecification(MessageRegistry.class);
                 val deficiencyOrigin = Identifier.classIdentifier(
-                        TypeIdentifier.eager(MessageRegistry.class, facetHolder.getSpecId().asString()));
+                        LogicalType.eager(MessageRegistry.class, facetHolder.getSpecId().asString()));
 
                 super.onFailure(
                         facetHolder, 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
index fa37065..8c77c75 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
@@ -34,6 +34,7 @@ import java.util.stream.Stream;
 import javax.annotation.Nullable;
 
 import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.repository.EntityState;
 import org.apache.isis.commons.collections.Can;
@@ -169,7 +170,7 @@ public final class ManagedObjects {
             @Nullable ManagedObject managedObject, 
             @NonNull final String separator) {
         return identify(managedObject)
-                .map(rootOid->rootOid.getObjectSpecId() + separator + rootOid.getIdentifier());
+                .map(rootOid->rootOid.getLogicalTypeName() + separator + rootOid.getIdentifier());
     }
 
     public static String stringifyElseFail(
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
index ca8be8e..cf6f9cc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
@@ -33,6 +33,8 @@ import javax.annotation.Nullable;
 
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.exceptions.UnrecoverableException;
+import org.apache.isis.applib.id.LogicalType;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.applib.services.metamodel.BeanSort;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Streams;
@@ -155,7 +157,16 @@ extends
      * <p>
      * The {@link ObjectSpecification} can be retrieved using {@link SpecificationLoader#lookupBySpecIdElseLoad(ObjectSpecId)}}.
      */
-    ObjectSpecId getSpecId();
+    @Deprecated
+    default ObjectSpecId getSpecId() {
+        throw _Exceptions.unsupportedOperation();
+    }
+    
+    LogicalType getLogicalType();
+    
+    default String getLogicalTypeName() {
+        return getLogicalType().getLogicalTypeName();
+    }
 
     /**
      * Returns an (immutable) "full" identifier for this specification.
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecIdToClassResolver.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolver.java
similarity index 87%
rename from core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecIdToClassResolver.java
rename to core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolver.java
index 0582cbc..a36366b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecIdToClassResolver.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolver.java
@@ -20,14 +20,14 @@ package org.apache.isis.core.metamodel.specloader;
 
 import java.util.Optional;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.NonNull;
 
-interface SpecIdToClassResolver {
+interface LogicalTypeResolver {
 
-    Optional<Class<?>> lookup(@NonNull ObjectSpecId specId);
+    Optional<LogicalType> lookup(@NonNull String logicalTypeName);
     
     void register(@NonNull ObjectSpecification spec);
     
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecIdToClassResolverDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolverDefault.java
similarity index 77%
rename from core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecIdToClassResolverDefault.java
rename to core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolverDefault.java
index e54865a..733806e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecIdToClassResolverDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/LogicalTypeResolverDefault.java
@@ -22,31 +22,31 @@ package org.apache.isis.core.metamodel.specloader;
 import java.util.Map;
 import java.util.Optional;
 
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.NonNull;
 
-class SpecIdToClassResolverDefault implements SpecIdToClassResolver {
+class LogicalTypeResolverDefault implements LogicalTypeResolver {
 
-    private final Map<ObjectSpecId, Class<?>> classBySpecId = _Maps.newConcurrentHashMap();
+    private final Map<String, LogicalType> logicalTypeByName = _Maps.newConcurrentHashMap();
 
     @Override
     public void clear() {
-        classBySpecId.clear();
+        logicalTypeByName.clear();
     }
 
     @Override
-    public Optional<Class<?>> lookup(final @NonNull ObjectSpecId specId) {
-        return Optional.ofNullable(classBySpecId.get(specId));
+    public Optional<LogicalType> lookup(final @NonNull String logicalTypeName) {
+        return Optional.ofNullable(logicalTypeByName.get(logicalTypeName));
     }
     
     @Override
     public void register(final @NonNull ObjectSpecification spec) {
         if(hasUsableSpecId(spec)) {
-            classBySpecId.put(spec.getSpecId(), spec.getCorrespondingClass());
+            logicalTypeByName.put(spec.getLogicalTypeName(), spec.getLogicalType());
         }
     }
     
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index cdb6444..5bdab4f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@ -22,10 +22,11 @@ import java.util.function.Consumer;
 
 import javax.annotation.Nullable;
 
+import org.apache.isis.applib.id.LogicalType;
+import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutor;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
@@ -100,9 +101,9 @@ public interface SpecificationLoader {
      * @param domainTypes
      * @return true if a specification could be loaded for all types, false otherwise
      */
-    boolean loadSpecifications(final Class<?>... domainTypes);
+    boolean loadSpecifications(Class<?>... domainTypes);
 
-    Class<?> lookupType(ObjectSpecId objectSpecId);
+    LogicalType lookupLogicalType(@Nullable String logicalTypeName);
 
     /**
      * queue {@code objectSpec} for later validation
@@ -113,34 +114,56 @@ public interface SpecificationLoader {
     // -- SHORTCUTS
 
     @Nullable
-    default ObjectSpecification loadSpecification(@Nullable Class<?> domainType) {
+    default ObjectSpecification loadSpecification(
+            final @Nullable Class<?> domainType) {
         return loadSpecification(domainType, IntrospectionState.TYPE_INTROSPECTED);
     }
 
     @Nullable
-    default ObjectSpecification loadSpecification(@Nullable ObjectSpecId objectSpecId) {
-        return loadSpecification(objectSpecId, IntrospectionState.TYPE_INTROSPECTED);
+    default ObjectSpecification loadSpecification(
+            final @Nullable String logicalTypeName) {
+        return loadSpecification(logicalTypeName, IntrospectionState.TYPE_INTROSPECTED);
     }
     
     @Nullable
     default ObjectSpecification loadSpecification(
-            @Nullable ObjectSpecId objectSpecId, 
-            @NonNull IntrospectionState introspectionState) {
+            final @Nullable LogicalType logicalType) {
+        return loadSpecification(logicalType.getCorrespondingClass(), IntrospectionState.TYPE_INTROSPECTED);
+    }
+    
+    @Nullable
+    default ObjectSpecification loadSpecification(
+            final @Nullable Bookmark bookmark) {
+        return loadSpecification(bookmark.getLogicalTypeName(), IntrospectionState.TYPE_INTROSPECTED);
+    }
+    
+    @Nullable
+    default ObjectSpecification loadSpecification(
+            final @Nullable String logicalTypeName, 
+            final @NonNull  IntrospectionState introspectionState) {
 
-        if(objectSpecId==null) {
+        if(logicalTypeName==null) {
             return null;
         }
-        val type = lookupType(objectSpecId);
-        return loadSpecification(type, introspectionState);
+        val logicalType = lookupLogicalType(logicalTypeName);
+        return loadSpecification(logicalType.getCorrespondingClass(), introspectionState);
     }
 
     /**
      * Lookup a specification that has bean loaded before.
      * @param objectSpecId
+     * //TODO[2533] rename
      */
     @Nullable
-    default ObjectSpecification lookupBySpecIdElseLoad(@Nullable ObjectSpecId objectSpecId) {
-        return loadSpecification(objectSpecId, IntrospectionState.TYPE_AND_MEMBERS_INTROSPECTED);
+    default ObjectSpecification lookupBySpecIdElseLoad(
+            final @Nullable String logicalTypeName) {
+        return loadSpecification(logicalTypeName, IntrospectionState.TYPE_AND_MEMBERS_INTROSPECTED);
+    }
+    
+    @Nullable
+    default ObjectSpecification lookupBySpecIdElseLoad(
+            final @Nullable LogicalType logicalType) {
+        return loadSpecification(logicalType.getCorrespondingClass(), IntrospectionState.TYPE_AND_MEMBERS_INTROSPECTED);
     }
     
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
index e99d481..81d201e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderDefault.java
@@ -38,6 +38,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.metamodel.BeanSort;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.commons.collections.Can;
@@ -65,7 +66,6 @@ import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutor
 import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutorDefault;
 import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutorForCollections;
 import org.apache.isis.core.metamodel.services.classsubstitutor.ClassSubstitutorRegistry;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.facetprocessor.FacetProcessor;
 import org.apache.isis.core.metamodel.specloader.postprocessor.PostProcessor;
@@ -121,7 +121,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
     private FacetProcessor facetProcessor;
 
     private final SpecificationCache<ObjectSpecification> cache = new SpecificationCacheDefault<>();
-    private final SpecIdToClassResolver specIdToClassResolver = new SpecIdToClassResolverDefault();
+    private final LogicalTypeResolver logicalTypeResolver = new LogicalTypeResolverDefault();
 
     /**
      * We only ever mark the meta-model as fully introspected if in {@link #isFullIntrospect() full} 
@@ -318,7 +318,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
 
     @Override
     public void disposeMetaModel() {
-        specIdToClassResolver.clear();
+        logicalTypeResolver.clear();
         cache.clear();
         validationResult.clear();
         log.info("Metamodel disposed.");
@@ -429,17 +429,19 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
     }
 
     @Override
-    public Class<?> lookupType(final @NonNull ObjectSpecId objectSpecId) {
-        Class<?> cls = specIdToClassResolver.lookup(objectSpecId)
+    public LogicalType lookupLogicalType(final @NonNull String logicalTypeName) {
+        val logicalType = logicalTypeResolver.lookup(logicalTypeName)
                 .orElse(null);
-        if(cls!=null) {
-            return cls;
+        if(logicalType!=null) {
+            return logicalType;
         }
         
-        // falling back assuming the specId equals the fqn of the corresponding class
-        // which might not always be true, hence the warning
-        //TODO desired behavior could be made a config option, eg. to throw an exception here instead
-        cls = ClassUtil.forNameElseNull(objectSpecId.asString());
+        //TODO[2533] if the logicalTypeName is not available and instead a fqcn was passed in, that should also be supported 
+        
+        // falling back assuming the logicalTypeName equals the fqn of the corresponding class
+        // which might not always be true, 
+        
+        val cls = ClassUtil.forNameElseNull(logicalTypeName);
         if(cls!=null) {
 
 //TODO yet it seems we rely on this kind of fallback from several code paths, so lets not emit any warnings yet ...              
@@ -448,15 +450,15 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
 //                    + "discovered by Spring during bootstrapping of this application.", 
 //                    objectSpecId.getSpecId(),
 //                    cls.getName());
-            return cls;
+            return LogicalType.fqcn(cls);
         }
         
         // immediately fail to not cause any NPEs further down the path
         throw _Exceptions.unrecoverableFormatted(
-                "Lookup for ObjectSpecId '%s' failed, also found no matching fully qualified "
+                "Lookup of logical-type-name '%s' failed, also found no matching fully qualified "
                 + "class name to use instead. This indicates, that the class we are not finding here"
                 + " is not discovered by Spring during bootstrapping of this application.",
-                objectSpecId.asString());
+                logicalTypeName);
     }
     
     // -- VALIDATION STUFF
@@ -517,7 +519,7 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         
         final ObjectSpecification spec = cache.computeIfAbsent(substitutedType, __->{
             val newSpec = createSpecification(substitutedType, beanClassifier.apply(type));
-            specIdToClassResolver.register(newSpec);
+            logicalTypeResolver.register(newSpec);
             return newSpec;
         });
 
@@ -628,5 +630,4 @@ public class SpecificationLoaderDefault implements SpecificationLoader {
         }
     }
 
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index a1ebf20..29ee7ef 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -19,7 +19,7 @@
 package org.apache.isis.core.metamodel.specloader.specimpl;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.collections.CanVector;
 import org.apache.isis.commons.internal.assertions._Assert;
@@ -91,7 +91,7 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
         final Identifier mixinIdentifier = mixinAction.getFacetedMethod().getIdentifier();
         val memberParameterClassNames = mixinIdentifier.getMemberParameterClassNames();
         identifier = Identifier.actionIdentifier(
-                TypeIdentifier.eager(
+                LogicalType.eager(
                         getOnType().getCorrespondingClass(),
                         getOnType().getSpecId().asString()),
                 getId(), 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
index 9018b26..96240ac 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java
@@ -33,7 +33,8 @@ import java.util.stream.Stream;
 import javax.enterprise.inject.Vetoed;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.applib.services.metamodel.BeanSort;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.commons.internal.base._Lazy;
@@ -74,7 +75,6 @@ import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
 import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
 import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -214,7 +214,7 @@ implements ObjectSpecification {
         this.isAbstract = ClassExtensions.isAbstract(introspectedClass);
 
         this.identifier = Identifier.classIdentifier(
-                TypeIdentifier.lazy(
+                LogicalType.lazy(
                         introspectedClass,
                         ()->specIdLazy.get().asString()));
 
@@ -228,10 +228,17 @@ implements ObjectSpecification {
         return FeatureType.OBJECT;
     }
 
-    @Override
+    @Override //TODO[2553] 
+    @Deprecated //use getLogicalTypeName() instead
     public ObjectSpecId getSpecId() {
         return specIdLazy.get();
     }
+    
+    @Override
+    public LogicalType getLogicalType() {
+        //TODO[2553] add memoization
+        return LogicalType.eager(correspondingClass, specIdLazy.get().asString());
+    }
         
     private ObjectSpecId lookupSpecId() {
         val objectSpecIdFacet = getFacet(ObjectSpecIdFacet.class);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
index 8debfdb..167fb51 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java
@@ -20,7 +20,7 @@ package org.apache.isis.core.metamodel.specloader.specimpl;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
@@ -129,7 +129,7 @@ public class OneToManyAssociationMixedIn extends OneToManyAssociationDefault imp
         val memberParameterNames = mixinIdentifier.getMemberParameterClassNames();
 
         identifier = Identifier.actionIdentifier(
-                TypeIdentifier.eager(
+                LogicalType.eager(
                         mixeeSpec.getCorrespondingClass(), 
                         mixeeSpec.getSpecId().asString()), 
                 getId(), 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
index 537379c..c487943 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java
@@ -20,7 +20,7 @@ package org.apache.isis.core.metamodel.specloader.specimpl;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Where;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
@@ -109,7 +109,7 @@ public class OneToOneAssociationMixedIn extends OneToOneAssociationDefault imple
         val memberParameterClassNames = mixinIdentifier.getMemberParameterClassNames();
 
         identifier = Identifier.actionIdentifier(
-                TypeIdentifier.eager(
+                LogicalType.eager(
                         mixeeSpec.getCorrespondingClass(), 
                         mixeeSpec.getSpecId().asString()),
                 getId(), 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index da67aa2..07dacf7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@ -27,6 +27,7 @@ import java.util.function.BiConsumer;
 import java.util.stream.Stream;
 
 import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.metamodel.BeanSort;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.commons.internal.base._Lazy;
@@ -375,6 +376,5 @@ implements FacetHolder {
                 .map(typeOfFacet -> ElementSpecificationProvider.of(typeOfFacet).getElementType());
     }
 
-    // --
 
 }
diff --git a/security/shiro/src/test/java/org/apache/isis/security/shiro/TypeIdentifierTestFactory.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/LogicalTypeTestFactory.java
similarity index 65%
copy from security/shiro/src/test/java/org/apache/isis/security/shiro/TypeIdentifierTestFactory.java
copy to core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/LogicalTypeTestFactory.java
index 7fa0571..cac40e7 100644
--- a/security/shiro/src/test/java/org/apache/isis/security/shiro/TypeIdentifierTestFactory.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/LogicalTypeTestFactory.java
@@ -16,21 +16,24 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.isis.security.shiro;
+package org.apache.isis.core.metamodel.adapter.oid;
 
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
-final class TypeIdentifierTestFactory {
-
-    static TypeIdentifier customer() {
-        return TypeIdentifier.fqcn(Customer.class);
+public class LogicalTypeTestFactory {
+    
+    public static LogicalType cus() {
+        return LogicalType.lazy(Customer.class, ()->"CUS");
     }
     
-    static TypeIdentifier order() {
-        return TypeIdentifier.fqcn(Order.class);
+    public static LogicalType cux() {
+        return LogicalType.lazy(Customer.class, ()->"CUX");
     }
     
+    public static LogicalType ord() {
+        return LogicalType.lazy(Order.class, ()->"ORD");
+    }
 }
 
 final class Customer {}
-final class Order {};
+final class Order {}
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_marshall.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_marshall.java
index 6b5e75f..abac218 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_marshall.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_marshall.java
@@ -24,8 +24,6 @@ import org.junit.Test;
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
-
 public class OidMarshallerTest_marshall {
 
     private Oid_Marshaller oidMarshaller;
@@ -37,7 +35,7 @@ public class OidMarshallerTest_marshall {
 
     @Test
     public void rootOid() {
-        final String marshal = oidMarshaller.marshal(Oid.Factory.root(ObjectSpecId.of("CUS"),  "123"));
+        final String marshal = oidMarshaller.marshal(Oid.Factory.root(LogicalTypeTestFactory.cus(),  "123"));
         assertThat(marshal, equalTo("CUS:123"));
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_roundtripping.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_roundtripping.java
index e65f99a..344dcd3 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_roundtripping.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_roundtripping.java
@@ -24,13 +24,11 @@ import org.junit.Test;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
-
 public class OidMarshallerTest_roundtripping {
 
     @Test
     public void rootOid() {
-        RootOid oid = Oid.Factory.root(ObjectSpecId.of("CUS"), "123");
+        RootOid oid = Oid.Factory.root(LogicalTypeTestFactory.cus(), "123");
 
         final String enString = oid.enString();
         final RootOid deString = RootOid.deString(enString);
@@ -39,7 +37,7 @@ public class OidMarshallerTest_roundtripping {
     
     @Test
     public void rootOid_withLegacyVersionIgnored() {
-        RootOid oid = Oid.Factory.root(ObjectSpecId.of("CUS"), "123");
+        RootOid oid = Oid.Factory.root(LogicalTypeTestFactory.cus(), "123");
 
         final String enString = oid.enString();
         final RootOid deString = RootOid.deString(enString + "^" + 90807L);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_unmarshal.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_unmarshal.java
index 205e9ae..e676f86 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_unmarshal.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshallerTest_unmarshal.java
@@ -25,8 +25,6 @@ import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
-
 /**
  * <dt>CUS:123</dt>
  * <dd>persistent root</dd>
@@ -69,7 +67,7 @@ public class OidMarshallerTest_unmarshal {
         final String oidStr = "CUS:123";
 
         final RootOid rootOid = oidMarshaller.unmarshal(oidStr, RootOid.class);
-        assertThat(rootOid.getObjectSpecId(), is(ObjectSpecId.of("CUS")));
+        assertThat(rootOid.getLogicalTypeName(), is("CUS"));
         assertThat(rootOid.getIdentifier(), is("123"));
 
         final Oid oid = oidMarshaller.unmarshal(oidStr, Oid.class);
@@ -81,7 +79,7 @@ public class OidMarshallerTest_unmarshal {
         final String oidStr = "com.planchase.ClassName:8";
 
         final RootOid rootOid = oidMarshaller.unmarshal(oidStr, RootOid.class);
-        assertThat(rootOid.getObjectSpecId(), is(ObjectSpecId.of("com.planchase.ClassName")));
+        assertThat(rootOid.getLogicalTypeName(), is("com.planchase.ClassName"));
         assertThat(rootOid.getIdentifier(), is("8"));
 
         final Oid oid = oidMarshaller.unmarshal(oidStr, Oid.class);
@@ -102,7 +100,7 @@ public class OidMarshallerTest_unmarshal {
         final String oidStr = "!CUS:123";
 
         final RootOid rootOid = oidMarshaller.unmarshal(oidStr, RootOid.class);
-        assertThat(rootOid.getObjectSpecId(), is(ObjectSpecId.of("CUS")));
+        assertThat(rootOid.getLogicalTypeName(), is("CUS"));
         assertThat(rootOid.getIdentifier(), is("123"));
 
         final Oid oid = oidMarshaller.unmarshal(oidStr, Oid.class);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidVersionTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidVersionTest.java
index acfa09a..eff870b 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidVersionTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/OidVersionTest.java
@@ -25,35 +25,35 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.applib.id.LogicalType;
 
 public class OidVersionTest  {
 
-    private ObjectSpecId cusObjectSpecId = ObjectSpecId.of("CUS");
-    private ObjectSpecId ordObjectSpecId = ObjectSpecId.of("ORD");
+    private LogicalType cus = LogicalTypeTestFactory.cus();
+    private LogicalType ord = LogicalTypeTestFactory.ord();
 
     private RootOid oid1, oid2;
 
     @Test
     public void whenEquivalent() throws Exception {
-        oid1 = Oid.Factory.root(cusObjectSpecId, "123");
-        oid2 = Oid.Factory.root(cusObjectSpecId, "123");
+        oid1 = Oid.Factory.root(cus, "123");
+        oid2 = Oid.Factory.root(cus, "123");
 
         assertThat(oid1, is(equalTo(oid2)));
     }
 
     @Test
     public void whenNotEquivalentById() throws Exception {
-        oid1 = Oid.Factory.root(cusObjectSpecId, "123");
-        oid2 = Oid.Factory.root(cusObjectSpecId, "124");
+        oid1 = Oid.Factory.root(cus, "123");
+        oid2 = Oid.Factory.root(cus, "124");
 
         assertThat(oid1, is(not(equalTo(oid2))));
     }
 
     @Test
     public void whenNotEquivalentByObjectSpecId() throws Exception {
-        oid1 = Oid.Factory.root(cusObjectSpecId, "123");
-        oid2 = Oid.Factory.root(ordObjectSpecId, "123");
+        oid1 = Oid.Factory.root(cus, "123");
+        oid2 = Oid.Factory.root(ord, "123");
 
         assertThat(oid1, is(not(equalTo(oid2))));
     }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefaultTest_valueSemantics_whenPersistent.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefaultTest_valueSemantics_whenPersistent.java
index 20c39d5..b8a2d09 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefaultTest_valueSemantics_whenPersistent.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidDefaultTest_valueSemantics_whenPersistent.java
@@ -22,24 +22,24 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.apache.isis.core.internaltestsupport.contract.ValueTypeContractTestAbstract;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
-public class RootOidDefaultTest_valueSemantics_whenPersistent extends ValueTypeContractTestAbstract<RootOid> {
+public class RootOidDefaultTest_valueSemantics_whenPersistent 
+extends ValueTypeContractTestAbstract<RootOid> {
 
     @Override
     protected List<RootOid> getObjectsWithSameValue() {
         return Arrays.asList(
-                Oid.Factory.root(ObjectSpecId.of("CUS"), "123"),
-                Oid.Factory.root(ObjectSpecId.of("CUS"), "123"),
-                Oid.Factory.root(ObjectSpecId.of("CUS"), "123"));
+                Oid.Factory.root(LogicalTypeTestFactory.cus(), "123"),
+                Oid.Factory.root(LogicalTypeTestFactory.cus(), "123"),
+                Oid.Factory.root(LogicalTypeTestFactory.cus(), "123"));
     }
 
     @Override
     protected List<RootOid> getObjectsWithDifferentValue() {
         return Arrays.asList(
                 //Oid.Factory.of(ObjectSpecId.of("CUS"), "123"),
-                Oid.Factory.root(ObjectSpecId.of("CUS"), "124"),
-                Oid.Factory.root(ObjectSpecId.of("CUX"), "123"));
+                Oid.Factory.root(LogicalTypeTestFactory.cus(), "124"),
+                Oid.Factory.root(LogicalTypeTestFactory.cux(), "123"));
     }
 
 }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidTest_create.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidTest_create.java
index 810f784..6c5ac96 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidTest_create.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/RootOidTest_create.java
@@ -23,16 +23,15 @@ import org.junit.Test;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import lombok.val;
 
 public class RootOidTest_create {
 
-
     @Test
     public void create() throws Exception {
-        ObjectSpecId objectSpecId = ObjectSpecId.of("CUS");
-        RootOid oid = Oid.Factory.root(objectSpecId, "123");
-        assertThat(oid.getObjectSpecId(), is(objectSpecId));
+        val logicalType = LogicalTypeTestFactory.cus();
+        RootOid oid = Oid.Factory.root(logicalType, "123");
+        assertThat(oid.getLogicalTypeName(), is(logicalType.getLogicalTypeName()));
         assertThat(oid.getIdentifier(), is("123"));
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facetapi/FeatureTypeTest_identifierFor.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facetapi/FeatureTypeTest_identifierFor.java
index 54e329a..1da5ef4 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facetapi/FeatureTypeTest_identifierFor.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facetapi/FeatureTypeTest_identifierFor.java
@@ -28,7 +28,7 @@ import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 public class FeatureTypeTest_identifierFor {
 
@@ -58,7 +58,7 @@ public class FeatureTypeTest_identifierFor {
     public void property_whenMethodNameIs_XYyyZzz() throws Exception {
         final Method method = SomeDomainClass.class.getMethod("getABigDecimal");
         final Identifier identifierFor = FeatureType.PROPERTY.identifierFor(
-                TypeIdentifier.fqcn(SomeDomainClass.class), method);
+                LogicalType.fqcn(SomeDomainClass.class), method);
         assertThat(identifierFor.getMemberName(), is("ABigDecimal")); // very
         // odd
         // compared
@@ -81,7 +81,7 @@ public class FeatureTypeTest_identifierFor {
     public void property_whenMethodNameIs_XxxxYyyZzz() throws Exception {
         final Method method = SomeDomainClass.class.getMethod("getAnotherBigDecimal");
         final Identifier identifierFor = FeatureType.PROPERTY.identifierFor(
-                TypeIdentifier.fqcn(SomeDomainClass.class), method);
+                LogicalType.fqcn(SomeDomainClass.class), method);
         assertThat(identifierFor.getMemberName(), is("anotherBigDecimal"));
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryJUnit4TestCase.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryJUnit4TestCase.java
index d927beb..2af781f 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryJUnit4TestCase.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryJUnit4TestCase.java
@@ -29,7 +29,7 @@ import org.junit.Before;
 import org.junit.Rule;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
@@ -118,7 +118,7 @@ public abstract class AbstractFacetFactoryJUnit4TestCase {
         }});
 
         facetHolder = new AbstractFacetFactoryTest.IdentifiedHolderImpl(
-                Identifier.propertyOrCollectionIdentifier(TypeIdentifier.fqcn(Customer.class), "firstName"));
+                Identifier.propertyOrCollectionIdentifier(LogicalType.fqcn(Customer.class), "firstName"));
         facetedMethod = FacetedMethod.createForProperty(AbstractFacetFactoryTest.Customer.class, "firstName");
         facetedMethodParameter = new FacetedMethodParameter(FeatureType.ACTION_PARAMETER_SCALAR, facetedMethod.getOwningType(), facetedMethod.getMethod(), String.class);
         
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java
index 23f9db2..b5248ed 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/AbstractFacetFactoryTest.java
@@ -26,7 +26,7 @@ import org.jmock.Expectations;
 import org.junit.Rule;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
@@ -94,7 +94,7 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
         // PRODUCTION
 
         facetHolder = new IdentifiedHolderImpl(
-                Identifier.propertyOrCollectionIdentifier(TypeIdentifier.fqcn(Customer.class), "firstName"));
+                Identifier.propertyOrCollectionIdentifier(LogicalType.fqcn(Customer.class), "firstName"));
         facetedMethod = FacetedMethod.createForProperty(Customer.class, "firstName");
         facetedMethodParameter = new FacetedMethodParameter(
                 FeatureType.ACTION_PARAMETER_SCALAR, facetedMethod.getOwningType(), facetedMethod.getMethod(), String.class
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newActionInteractionEvent.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newActionInteractionEvent.java
index ac8c5bc..1c0e981 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newActionInteractionEvent.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newActionInteractionEvent.java
@@ -28,7 +28,7 @@ import static org.junit.Assert.assertSame;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 import static junit.framework.Assert.assertEquals;
 
@@ -43,7 +43,7 @@ public class DomainEventHelperTest_newActionInteractionEvent {
     @Test
     public void defaultEventType() throws Exception {
         final SomeDomainObject sdo = new SomeDomainObject();
-        final Identifier identifier = Identifier.actionIdentifier(TypeIdentifier.fqcn(SomeDomainObject.class), "foo", new Class[]{int.class, String.class});
+        final Identifier identifier = Identifier.actionIdentifier(LogicalType.fqcn(SomeDomainObject.class), "foo", new Class[]{int.class, String.class});
 
         Utils.domainEventHelper();
         final ActionDomainEvent<Object> ev = DomainEventHelper.newActionDomainEvent(
@@ -58,7 +58,7 @@ public class DomainEventHelperTest_newActionInteractionEvent {
     @Test
     public void actionInvokedEventDefaultEventType() throws Exception {
         final SomeDomainObject sdo = new SomeDomainObject();
-        final Identifier identifier = Identifier.actionIdentifier(TypeIdentifier.fqcn(SomeDomainObject.class), "foo", new Class[]{int.class, String.class});
+        final Identifier identifier = Identifier.actionIdentifier(LogicalType.fqcn(SomeDomainObject.class), "foo", new Class[]{int.class, String.class});
 
         Utils.domainEventHelper();
         final ActionDomainEvent<Object> ev = DomainEventHelper.newActionDomainEvent(
@@ -73,7 +73,7 @@ public class DomainEventHelperTest_newActionInteractionEvent {
     @Test
     public void customEventType() throws Exception {
         final SomeDomainObject sdo = new SomeDomainObject();
-        final Identifier identifier = Identifier.actionIdentifier(TypeIdentifier.fqcn(SomeDomainObject.class), "foo", new Class[]{int.class, String.class});
+        final Identifier identifier = Identifier.actionIdentifier(LogicalType.fqcn(SomeDomainObject.class), "foo", new Class[]{int.class, String.class});
 
         Utils.domainEventHelper();
         final ActionDomainEvent<SomeDomainObject> ev = DomainEventHelper.newActionDomainEvent(
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forAdd.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forAdd.java
index 40e08fc..d586a41 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forAdd.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forAdd.java
@@ -29,7 +29,7 @@ import static org.junit.Assert.assertSame;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.events.domain.AbstractDomainEvent;
 import org.apache.isis.applib.events.domain.CollectionDomainEvent;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 public class DomainEventHelperTest_newCollectionDomainEvent_forAdd {
 
@@ -45,7 +45,7 @@ public class DomainEventHelperTest_newCollectionDomainEvent_forAdd {
         final SomeDomainObject sdo = new SomeDomainObject();
         final SomeReferencedObject other = new SomeReferencedObject();
         final Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "references");
+                LogicalType.fqcn(SomeDomainObject.class), "references");
 
         final CollectionDomainEvent<Object, Object> ev = Utils.domainEventHelper().newCollectionDomainEvent(
                 CollectionDomainEvent.Default.class, null, identifier, sdo, CollectionDomainEvent.Of.ADD_TO, other);
@@ -60,7 +60,7 @@ public class DomainEventHelperTest_newCollectionDomainEvent_forAdd {
         final SomeDomainObject sdo = new SomeDomainObject();
         final SomeReferencedObject other = new SomeReferencedObject();
         final Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "references");
+                LogicalType.fqcn(SomeDomainObject.class), "references");
 
         final CollectionDomainEvent<Object, Object> ev = Utils.domainEventHelper().newCollectionDomainEvent(
                 CollectionDomainEvent.Default.class, AbstractDomainEvent.Phase.EXECUTED, identifier, sdo, CollectionDomainEvent.Of.ADD_TO, other);
@@ -75,7 +75,7 @@ public class DomainEventHelperTest_newCollectionDomainEvent_forAdd {
         final SomeDomainObject sdo = new SomeDomainObject();
         final SomeReferencedObject other = new SomeReferencedObject();
         final Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "references");
+                LogicalType.fqcn(SomeDomainObject.class), "references");
 
         final CollectionDomainEvent<SomeDomainObject, SomeReferencedObject> ev = Utils.domainEventHelper().newCollectionDomainEvent(
                 SomeDomainObjectCollectionDomainEvent.class, AbstractDomainEvent.Phase.EXECUTED, identifier, sdo, CollectionDomainEvent.Of.ADD_TO, other);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forRemove.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forRemove.java
index 78b74fe..b07c9e2 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forRemove.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newCollectionDomainEvent_forRemove.java
@@ -29,7 +29,7 @@ import static org.junit.Assert.assertSame;
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.events.domain.AbstractDomainEvent;
 import org.apache.isis.applib.events.domain.CollectionDomainEvent;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 public class DomainEventHelperTest_newCollectionDomainEvent_forRemove {
 
@@ -45,7 +45,7 @@ public class DomainEventHelperTest_newCollectionDomainEvent_forRemove {
         SomeDomainObject sdo = new SomeDomainObject();
         SomeReferencedObject other = new SomeReferencedObject();
         Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "references");
+                LogicalType.fqcn(SomeDomainObject.class), "references");
 
         final CollectionDomainEvent<Object, Object> ev = Utils.domainEventHelper().newCollectionDomainEvent(
                 CollectionDomainEvent.Default.class, AbstractDomainEvent.Phase.EXECUTED, identifier, sdo, CollectionDomainEvent.Of.REMOVE_FROM, other);
@@ -60,7 +60,7 @@ public class DomainEventHelperTest_newCollectionDomainEvent_forRemove {
         SomeDomainObject sdo = new SomeDomainObject();
         SomeReferencedObject other = new SomeReferencedObject();
         Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "references");
+                LogicalType.fqcn(SomeDomainObject.class), "references");
 
         final CollectionDomainEvent<Object, Object> ev = Utils.domainEventHelper().newCollectionDomainEvent(
                 CollectionDomainEvent.Default.class, AbstractDomainEvent.Phase.EXECUTED, identifier, sdo, CollectionDomainEvent.Of.REMOVE_FROM, other);
@@ -75,7 +75,7 @@ public class DomainEventHelperTest_newCollectionDomainEvent_forRemove {
         SomeDomainObject sdo = new SomeDomainObject();
         SomeReferencedObject other = new SomeReferencedObject();
         Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "references");
+                LogicalType.fqcn(SomeDomainObject.class), "references");
 
         final CollectionDomainEvent<SomeDomainObject, SomeReferencedObject> ev = Utils.domainEventHelper().newCollectionDomainEvent(
                 SomeDomainObjectCollectionRemovedFromDomainEvent.class, AbstractDomainEvent.Phase.EXECUTED, identifier, sdo, CollectionDomainEvent.Of.REMOVE_FROM, other);
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forClear.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forClear.java
index fb0b62c..258d5a2 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forClear.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forClear.java
@@ -29,7 +29,7 @@ import static org.junit.Assert.assertSame;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.events.domain.PropertyDomainEvent;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 import static junit.framework.Assert.assertEquals;
 
@@ -45,7 +45,7 @@ public class DomainEventHelperTest_newPropertyDomainEvent_forClear {
 
         SomeDomainObject sdo = new SomeDomainObject();
         Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "someDateProperty");
+                LogicalType.fqcn(SomeDomainObject.class), "someDateProperty");
         LocalDate oldValue = LocalDate.of(2013,4,1);
         LocalDate newValue = null;
 
@@ -64,7 +64,7 @@ public class DomainEventHelperTest_newPropertyDomainEvent_forClear {
 
         SomeDomainObject sdo = new SomeDomainObject();
         Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "someDateProperty");
+                LogicalType.fqcn(SomeDomainObject.class), "someDateProperty");
         LocalDate oldValue = LocalDate.of(2013,4,1);
         LocalDate newValue = null;
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forModify.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forModify.java
index 35666b9..8c130e5 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forModify.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/DomainEventHelperTest_newPropertyDomainEvent_forModify.java
@@ -27,7 +27,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.events.domain.PropertyDomainEvent;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 public class DomainEventHelperTest_newPropertyDomainEvent_forModify {
 
@@ -41,7 +41,7 @@ public class DomainEventHelperTest_newPropertyDomainEvent_forModify {
 
         SomeDomainObject sdo = new SomeDomainObject();
         Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "someDateProperty");
+                LogicalType.fqcn(SomeDomainObject.class), "someDateProperty");
         LocalDate oldValue = LocalDate.of(2013,4,1);
         LocalDate newValue = LocalDate.of(2013,5,2);
 
@@ -60,7 +60,7 @@ public class DomainEventHelperTest_newPropertyDomainEvent_forModify {
 
         SomeDomainObject sdo = new SomeDomainObject();
         Identifier identifier = Identifier.propertyOrCollectionIdentifier(
-                TypeIdentifier.fqcn(SomeDomainObject.class), "someDateProperty");
+                LogicalType.fqcn(SomeDomainObject.class), "someDateProperty");
         LocalDate oldValue = LocalDate.of(2013,4,1);
         LocalDate newValue = LocalDate.of(2013,5,2);
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactoryTest.java
index e336e5f..a2246a7 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactoryTest.java
@@ -34,6 +34,7 @@ import static org.junit.Assert.assertFalse;
 
 import org.apache.isis.applib.annotation.Bounding;
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.commons.having.HasUniqueId;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.config.metamodel.facets.EditingObjectsConfiguration;
@@ -58,7 +59,6 @@ import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFac
 import org.apache.isis.core.metamodel.facets.object.publish.entitychange.EntityChangePublishingFacet;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.choices.ChoicesFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 import lombok.val;
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/ObjectTypeAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/ObjectTypeAnnotationFacetFactoryTest.java
index 1aa4707..8c6a3b6 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/ObjectTypeAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/domainobject/ObjectTypeAnnotationFacetFactoryTest.java
@@ -28,11 +28,11 @@ import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
 import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
 import org.apache.isis.core.metamodel.facets.ObjectSpecIdFacetFactory.ProcessObjectSpecIdContext;
 import org.apache.isis.core.metamodel.facets.object.domainobject.objectspecid.ObjectSpecIdFacetForDomainObjectAnnotation;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 public class ObjectTypeAnnotationFacetFactoryTest extends AbstractFacetFactoryJUnit4TestCase {
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinIntendedAs.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinIntendedAs.java
index 5fe3636..174e3f2 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinIntendedAs.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinIntendedAs.java
@@ -26,7 +26,7 @@ import org.mockito.Mockito;
 import static org.mockito.Mockito.when;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.Mode;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.inject.ServiceInjector;
@@ -91,7 +91,7 @@ abstract class MixinIntendedAs {
     protected FacetHolder runTypeContextOn(Class<?> type) {
 
         val facetHolder = new AbstractFacetFactoryTest.IdentifiedHolderImpl(
-              Identifier.classIdentifier(TypeIdentifier.fqcn(type)));
+              Identifier.classIdentifier(LogicalType.fqcn(type)));
         facetHolder.setMetaModelContext(metaModelContext);
 
         val processClassContext =
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetDerivedFromClassNameFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetDerivedFromClassNameFactoryTest.java
index 5b59eb8..1445001 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetDerivedFromClassNameFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/object/objectspecid/ObjectSpecIdFacetDerivedFromClassNameFactoryTest.java
@@ -28,11 +28,11 @@ import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.facets.AbstractFacetFactoryJUnit4TestCase;
 import org.apache.isis.core.metamodel.facets.ObjectSpecIdFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.classname.ObjectSpecIdFacetDerivedFromClassName;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.classname.ObjectSpecIdFacetDerivedFromClassNameFactory;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 public class ObjectSpecIdFacetDerivedFromClassNameFactoryTest extends AbstractFacetFactoryJUnit4TestCase {
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/id/TypeIdentifierTestFactory.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/id/TypeIdentifierTestFactory.java
index 58c8459..d61e419 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/id/TypeIdentifierTestFactory.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/id/TypeIdentifierTestFactory.java
@@ -18,7 +18,7 @@
  */
 package org.apache.isis.core.metamodel.id;
 
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 import lombok.experimental.UtilityClass;
 
@@ -27,8 +27,8 @@ public final class TypeIdentifierTestFactory {
     
     private static class Customer {};
     
-    public static TypeIdentifier newCustomer() {
-        return TypeIdentifier.fqcn(Customer.class);
+    public static LogicalType newCustomer() {
+        return LogicalType.fqcn(Customer.class);
     }
 
 }
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java
index 3cc3e22..402f616 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java
@@ -20,6 +20,8 @@ package org.apache.isis.core.metamodel.spec;
 
 import org.junit.Test;
 
+import org.apache.isis.applib.id.ObjectSpecId;
+
 public class ObjectSpecIdTest_constructor {
 
     @Test
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java
index be0337a..b3808d7 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java
@@ -21,6 +21,7 @@ package org.apache.isis.core.metamodel.spec;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.internaltestsupport.contract.ValueTypeContractTestAbstract;
 
 public class ObjectSpecIdTest_valueSemantics extends ValueTypeContractTestAbstract<ObjectSpecId> {
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefaultTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefaultTest.java
index 4618e32..96d2850 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefaultTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationCacheDefaultTest.java
@@ -30,14 +30,18 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertSame;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2.Mode;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.adapter.oid.LogicalTypeTestFactory;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.val;
 
 public class SpecificationCacheDefaultTest {
+    
+    private LogicalType cus = LogicalTypeTestFactory.cus();
+    private LogicalType ord = LogicalTypeTestFactory.ord();
 
     @Rule
     public JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(Mode.INTERFACES_ONLY);
@@ -48,7 +52,7 @@ public class SpecificationCacheDefaultTest {
     private ObjectSpecification orderSpec;
 
     private SpecificationCache<ObjectSpecification> specificationCache = new SpecificationCacheDefault<>();
-    private SpecIdToClassResolver specIdToClassResolver = new SpecIdToClassResolverDefault();
+    private LogicalTypeResolver specIdToClassResolver = new LogicalTypeResolverDefault();
 
     @Before
     public void setUp() throws Exception {
@@ -57,14 +61,14 @@ public class SpecificationCacheDefaultTest {
             allowing(customerSpec).getCorrespondingClass();
             will(returnValue(Customer.class));
 
-            allowing(customerSpec).getSpecId();
-            will(returnValue(ObjectSpecId.of("CUS")));
+            allowing(customerSpec).getLogicalType();
+            will(returnValue(cus));
             
             allowing(orderSpec).getCorrespondingClass();
             will(returnValue(Order.class));
             
-            allowing(orderSpec).getSpecId();
-            will(returnValue(ObjectSpecId.of("ORD")));
+            allowing(orderSpec).getLogicalType();
+            will(returnValue(ord));
             
         }});
     }
@@ -106,7 +110,7 @@ public class SpecificationCacheDefaultTest {
 
     @Test
     public void getByObjectType_whenNotSet() {
-        val type = specIdToClassResolver.lookup(ObjectSpecId.of("CUS"));
+        val type = specIdToClassResolver.lookup(cus.getLogicalTypeName());
         assertFalse(type.isPresent());
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java
index 5db08f4..c0f2881 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/testspec/ObjectSpecificationStub.java
@@ -27,7 +27,7 @@ import java.util.Set;
 import java.util.stream.Stream;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.metamodel.BeanSort;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -42,7 +42,6 @@ import org.apache.isis.core.metamodel.interactions.ObjectTitleContext;
 import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
 import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -50,18 +49,21 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState;
 
+import lombok.Synchronized;
 import lombok.val;
 
-public class ObjectSpecificationStub extends FacetHolderImpl implements ObjectSpecification {
+public class ObjectSpecificationStub 
+extends FacetHolderImpl
+implements ObjectSpecification {
 
     private ObjectAction action;
     public List<ObjectAssociation> fields = _Lists.newArrayList();
     private Set<ObjectSpecification> subclasses = Collections.emptySet();
     private String title;
     /**
-     * lazily derived, see {@link #getSpecId()} 
+     * lazily derived, see {@link #getLogicalType()} 
      */
-    private ObjectSpecId specId;
+    private LogicalType logicalType;
 
     private ObjectSpecification elementSpecification;
     private final Class<?> correspondingClass;
@@ -126,12 +128,14 @@ public class ObjectSpecificationStub extends FacetHolderImpl implements ObjectSp
         return name;
     }
 
+    @Synchronized
     @Override
-    public ObjectSpecId getSpecId() {
-        if(specId == null) {
-            specId = getFacet(ObjectSpecIdFacet.class).value();
+    public LogicalType getLogicalType() {
+        if(logicalType == null) {
+            val logicalTypeName = getFacet(ObjectSpecIdFacet.class).value().asString();
+            logicalType = LogicalType.eager(correspondingClass, logicalTypeName);
         }
-        return specId;
+        return logicalType;
     }
 
     @Override
@@ -257,7 +261,7 @@ public class ObjectSpecificationStub extends FacetHolderImpl implements ObjectSp
 
     @Override
     public Identifier getIdentifier() {
-        return Identifier.classIdentifier(TypeIdentifier.fqcn(correspondingClass));
+        return Identifier.classIdentifier(LogicalType.fqcn(correspondingClass));
     }
 
     @Override
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMemento.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMemento.java
index a3b62db..56b8071 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMemento.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMemento.java
@@ -24,19 +24,19 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Optional;
 
+import org.apache.isis.applib.id.HasLogicalType;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.collections.Cardinality;
 import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
-
 
 /**
  * @since 2.0
  */
-public interface ObjectMemento extends Serializable {
+public interface ObjectMemento extends HasLogicalType, Serializable {
 
     String asString();
-
+    
     /**
      * Returns a bookmark only if 
      * {@link org.apache.isis.viewer.wicket.viewer.services.mementos.ObjectMementoWkt.RecreateStrategy#LOOKUP} and
@@ -52,20 +52,18 @@ public interface ObjectMemento extends Serializable {
      * Returns {@code null} otherwise. 
      */
     Bookmark asHintingBookmarkIfSupported();
-
-    ObjectSpecId getObjectSpecId();
-
+    
     // -- FACTORIES
 
     static ObjectMemento wrapMementoList(
             Collection<ObjectMemento> container, 
-            ObjectSpecId specId) {
+            LogicalType logicalType) {
 
         // ArrayList is serializable
         if(container instanceof ArrayList) {
-            return ObjectMementoCollection.of((ArrayList<ObjectMemento>)container, specId);
+            return ObjectMementoCollection.of((ArrayList<ObjectMemento>)container, logicalType);
         }
-        return ObjectMementoCollection.of(_Lists.newArrayList(container), specId);
+        return ObjectMementoCollection.of(_Lists.newArrayList(container), logicalType);
     }
 
     // ArrayList is serializable
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoCollection.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoCollection.java
index 8c583ab..9ea8a2d 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoCollection.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoCollection.java
@@ -20,11 +20,12 @@ package org.apache.isis.core.runtime.memento;
 
 import java.util.ArrayList;
 
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 import lombok.Getter;
+import lombok.NonNull;
 import lombok.Value;
 
 /**
@@ -38,8 +39,10 @@ public final class ObjectMementoCollection implements ObjectMemento {
     private static final long serialVersionUID = 1L;
 
     private final ArrayList<ObjectMemento> container; 
-    @Getter(onMethod = @__({@Override})) private final ObjectSpecId objectSpecId;
 
+    @Getter(onMethod_ = {@Override})
+    @NonNull private final LogicalType logicalType;
+    
     @Override
     public String asString() {
         return getContainer().toString();
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoForEmpty.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoForEmpty.java
index 7937cb0..adbcee7 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoForEmpty.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoForEmpty.java
@@ -18,8 +18,8 @@
  */
 package org.apache.isis.core.runtime.memento;
 
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 import lombok.Getter;
 import lombok.NonNull;
@@ -30,14 +30,14 @@ public class ObjectMementoForEmpty implements ObjectMemento {
 
     private static final long serialVersionUID = 1L;
     
-    @Getter(onMethod = @__(@Override))
-    @NonNull private ObjectSpecId objectSpecId;
+    @Getter(onMethod_ = {@Override})
+    @NonNull private LogicalType logicalType;
 
     @Override
     public String asString() {
-        return getObjectSpecId().asString();
+        return getLogicalTypeName();
     }
-
+    
     @Override
     public Bookmark asBookmarkIfSupported() {
         return null;
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoService.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoService.java
index 2c9be7f..4c2bd75 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoService.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/memento/ObjectMementoService.java
@@ -18,16 +18,14 @@
  */
 package org.apache.isis.core.runtime.memento;
 
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 
 import lombok.NonNull;
 
 /**
  * @since 2.0
- * 
- *
  */
 public interface ObjectMementoService {
 
@@ -37,7 +35,7 @@ public interface ObjectMementoService {
 
     ObjectMemento mementoForPojo(Object pojo);
     
-    ObjectMemento mementoForPojos(Iterable<Object> iterablePojos, ObjectSpecId specId);
+    ObjectMemento mementoForPojos(Iterable<Object> iterablePojos, LogicalType logicalType);
 
     ManagedObject reconstructObject(ObjectMemento memento);
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
index d09ec39..12c8bc9 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
@@ -44,7 +44,6 @@ import org.apache.isis.commons.internal.memento._Mementos.SerializingAdapter;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
 import lombok.val;
@@ -79,7 +78,7 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
             return null;
         }
         try {
-            val spec = specificationLoader.loadSpecification(ObjectSpecId.of(bookmark.getObjectType()));
+            val spec = specificationLoader.loadSpecification(bookmark);
             val identifier = bookmark.getIdentifier();
             val objectLoadRequest = ObjectLoader.Request.of(spec, identifier);
             
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
index ee1162e..adb0c42 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandExecutorServiceDefault.java
@@ -387,7 +387,7 @@ public class CommandExecutorServiceDefault implements CommandExecutorService {
     }
 
     private ManagedObject adapterFor(final RootOid oid) {
-        val objectSpec = specificationLoader.loadSpecification(oid.getObjectSpecId());
+        val objectSpec = specificationLoader.loadSpecification(oid.getLogicalTypeName());
         val loadRequest = ObjectLoader.Request.of(objectSpec, oid.getIdentifier());
         return objectSpec.getMetaModelContext().getObjectManager().loadObject(loadRequest);
     }
diff --git a/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/seed/scripts/AbstractRoleAndPermissionsFixtureScript.java b/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/seed/scripts/AbstractRoleAndPermissionsFixtureScript.java
index 2352337..1b62e8c 100644
--- a/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/seed/scripts/AbstractRoleAndPermissionsFixtureScript.java
+++ b/extensions/security/secman/persistence-jdo/src/main/java/org/apache/isis/extensions/secman/jdo/seed/scripts/AbstractRoleAndPermissionsFixtureScript.java
@@ -25,9 +25,9 @@ import java.util.stream.Collectors;
 
 import javax.inject.Inject;
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureType;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.extensions.secman.api.permission.ApplicationPermissionMode;
diff --git a/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/FullCalendarWithEventHandling.java b/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/FullCalendarWithEventHandling.java
index a9407a5..9f31483 100644
--- a/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/FullCalendarWithEventHandling.java
+++ b/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/FullCalendarWithEventHandling.java
@@ -70,7 +70,7 @@ final class FullCalendarWithEventHandling extends FullCalendar {
         final ObjectManager objectManager = commonContext.getObjectManager();
         final IsisAppCommonContext webAppCommonContext = IsisAppCommonContext.of(metaModelContext);
 
-        val spec = specificationLoader.loadSpecification(oid.getObjectSpecId());
+        val spec = specificationLoader.loadSpecification(oid.getLogicalTypeName());
         val objectId = oid.getIdentifier();
         val managedObject = objectManager.loadObject(ObjectLoader.Request.of(spec, objectId));
 
diff --git a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
index a8a757a..2357a6d 100644
--- a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
+++ b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
@@ -126,7 +126,7 @@ implements EntityFacet {
 
         _Assert.assertTrue(entitySpec.isEntity());
 
-        val rootOid = Oid.Factory.root(entitySpec.getSpecId(), identifier);
+        val rootOid = Oid.Factory.root(entitySpec.getLogicalType(), identifier);
 
         log.debug("fetchEntity; rootOid={}", rootOid);
 
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java
index 1aa95f3..65060d5 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForClauseAbstract.java
@@ -19,9 +19,8 @@
 package org.apache.isis.persistence.jdo.metamodel.facets.object.query;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
@@ -80,10 +79,10 @@ abstract class VisitorForClauseAbstract implements MetaModelValidatorVisiting.Vi
         }
 
         val cls = objectSpec.getCorrespondingClass();
-        if (getSpecificationLoader().loadSpecification(ObjectSpecId.of(classNameFromClause))==null) {
+        if (getSpecificationLoader().loadSpecification(classNameFromClause)==null) {
             validator.onFailure(
                     objectSpec,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                    Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     "%s: error in JDOQL query, class name for '%s' clause not recognized (JDOQL : %s)",
                     cls.getName(), clause, query);
             return;
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java
index ac9747e..1529cdc 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForFromClause.java
@@ -21,9 +21,8 @@ package org.apache.isis.persistence.jdo.metamodel.facets.object.query;
 import java.util.Objects;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.metamodel.spec.Hierarchical;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
 
@@ -52,14 +51,14 @@ class VisitorForFromClause extends VisitorForClauseAbstract {
         if (Objects.equals(classNameFromClause, cls.getName())) {
             return;
         }
-        val fromSpec = getSpecificationLoader().loadSpecification(ObjectSpecId.of(classNameFromClause));
+        val fromSpec = getSpecificationLoader().loadSpecification(classNameFromClause);
         val subclasses = fromSpec.subclasses(Hierarchical.Depth.TRANSITIVE);
         if(subclasses.contains(objectSpec)) {
             return;
         }
         validator.onFailure(
                 objectSpec,
-                Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                Identifier.classIdentifier(LogicalType.fqcn(cls)),
                 "%s: error in JDOQL query, class name after '%s' clause should be same as class name on which annotated, or one of its supertypes (JDOQL : %s)",
                 cls.getName(), clause, query);
     }
diff --git a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java
index 7987dfe..79eb0f4 100644
--- a/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java
+++ b/persistence/jdo/metamodel/src/main/java/org/apache/isis/persistence/jdo/metamodel/facets/object/query/VisitorForVariablesClause.java
@@ -19,8 +19,7 @@
 package org.apache.isis.persistence.jdo.metamodel.facets.object.query;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.specimpl.IntrospectionState;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidator;
@@ -50,7 +49,7 @@ class VisitorForVariablesClause extends VisitorForClauseAbstract {
         val cls = objectSpec.getCorrespondingClass();
         val objectSpecification = getSpecificationLoader()
                 .loadSpecification(
-                        ObjectSpecId.of(classNameFromClause), 
+                        classNameFromClause, 
                         IntrospectionState.TYPE_INTROSPECTED);
         
         JdoPersistenceCapableFacet persistenceCapableFacet =
@@ -59,7 +58,7 @@ class VisitorForVariablesClause extends VisitorForClauseAbstract {
         if(persistenceCapableFacet == null) {
             validator.onFailure(
                     objectSpec,
-                    Identifier.classIdentifier(TypeIdentifier.fqcn(cls)),
+                    Identifier.classIdentifier(LogicalType.fqcn(cls)),
                     "%s: error in JDOQL query, class name for '%s' clause is not annotated as @PersistenceCapable (JDOQL : %s)",
                     cls.getName(), clause, query);
             return;
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/discriminator/GivenJdoDiscriminatorAnnotationFacetFactoryTest.java b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/discriminator/GivenJdoDiscriminatorAnnotationFacetFactoryTest.java
index c50efcd..f2dd166 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/discriminator/GivenJdoDiscriminatorAnnotationFacetFactoryTest.java
+++ b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/discriminator/GivenJdoDiscriminatorAnnotationFacetFactoryTest.java
@@ -21,12 +21,12 @@ package org.apache.isis.persistence.jdo.metamodel.facets.object.discriminator;
 import javax.jdo.annotations.Discriminator;
 import javax.jdo.annotations.PersistenceCapable;
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.FacetFactory;
 import org.apache.isis.core.metamodel.facets.ObjectSpecIdFacetFactory;
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.persistence.jdo.metamodel.testing.AbstractFacetFactoryTest;
 import org.apache.isis.persistence.jdo.provider.metamodel.facets.object.discriminator.JdoDiscriminatorFacet;
 
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/TypeIdentifierTestFactory.java b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/TypeIdentifierTestFactory.java
index 22a3868..c0be502 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/TypeIdentifierTestFactory.java
+++ b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/facets/object/version/TypeIdentifierTestFactory.java
@@ -18,14 +18,14 @@
  */
 package org.apache.isis.persistence.jdo.metamodel.facets.object.version;
 
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 final class TypeIdentifierTestFactory {
 
     private static class Customer {};
     
-    static TypeIdentifier customer() {
-        return TypeIdentifier.fqcn(Customer.class);
+    static LogicalType customer() {
+        return LogicalType.fqcn(Customer.class);
     }
     
 }
diff --git a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java
index ea70fe7..38e4d2b 100644
--- a/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java
+++ b/persistence/jdo/metamodel/src/test/java/org/apache/isis/persistence/jdo/metamodel/testing/AbstractFacetFactoryTest.java
@@ -26,7 +26,7 @@ import org.jmock.Expectations;
 import org.junit.Rule;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.repository.EntityState;
 import org.apache.isis.commons.collections.ImmutableEnumSet;
@@ -99,7 +99,7 @@ public abstract class AbstractFacetFactoryTest extends TestCase {
         // PRODUCTION
 
         facetHolder = new IdentifiedHolderImpl(
-                Identifier.propertyOrCollectionIdentifier(TypeIdentifier.fqcn(Customer.class), "firstName"));
+                Identifier.propertyOrCollectionIdentifier(LogicalType.fqcn(Customer.class), "firstName"));
         facetedMethod = FacetedMethod.createForProperty(Customer.class, "firstName");
         facetedMethodParameter = new FacetedMethodParameter(
                 FeatureType.ACTION_PARAMETER_SCALAR, facetedMethod.getOwningType(), facetedMethod.getMethod(), String.class
diff --git a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/domainmodel/SpecLoaderTest.java b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/domainmodel/SpecLoaderTest.java
index 45fd7e2..3763cbe 100644
--- a/regressiontests/stable/src/test/java/org/apache/isis/testdomain/domainmodel/SpecLoaderTest.java
+++ b/regressiontests/stable/src/test/java/org/apache/isis/testdomain/domainmodel/SpecLoaderTest.java
@@ -64,12 +64,12 @@ class SpecLoaderTest {
         val spec1 = specificationLoader.loadSpecification(type);
         assertNotNull(spec1);
         
-        val specId = spec1.getSpecId();
+        val logicalType = spec1.getLogicalType();
         
-        val spec2 = specificationLoader.loadSpecification(specId);
+        val spec2 = specificationLoader.loadSpecification(logicalType);
         assertNotNull(spec2);
         
-        assertEquals(spec1.getSpecId(), spec2.getSpecId());
+        assertEquals(spec1.getLogicalType(), spec2.getLogicalType());
     }
     
     private static Stream<Class<?>> providePrimitiveTypes() {
diff --git a/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java b/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java
index c54f3a8..9dc9214 100644
--- a/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java
+++ b/security/shiro/src/main/java/org/apache/isis/security/shiro/authorization/AuthorizorShiro.java
@@ -87,7 +87,7 @@ public class AuthorizorShiro implements Authorizor {
     }
 
     private String asPermissionsString(Identifier identifier) {
-        val logicalTypeName = identifier.getTypeIdentifier().getLogicalTypeNameFormatted(":", ":");
+        val logicalTypeName = identifier.getLogicalType().getLogicalTypeNameFormatted(":", ":");
         return logicalTypeName + ":" + identifier.getMemberName();
     }
 
diff --git a/security/shiro/src/test/java/org/apache/isis/security/shiro/TypeIdentifierTestFactory.java b/security/shiro/src/test/java/org/apache/isis/security/shiro/TypeIdentifierTestFactory.java
index 7fa0571..5943a9d 100644
--- a/security/shiro/src/test/java/org/apache/isis/security/shiro/TypeIdentifierTestFactory.java
+++ b/security/shiro/src/test/java/org/apache/isis/security/shiro/TypeIdentifierTestFactory.java
@@ -18,16 +18,16 @@
  */
 package org.apache.isis.security.shiro;
 
-import org.apache.isis.applib.id.TypeIdentifier;
+import org.apache.isis.applib.id.LogicalType;
 
 final class TypeIdentifierTestFactory {
 
-    static TypeIdentifier customer() {
-        return TypeIdentifier.fqcn(Customer.class);
+    static LogicalType customer() {
+        return LogicalType.fqcn(Customer.class);
     }
     
-    static TypeIdentifier order() {
-        return TypeIdentifier.fqcn(Order.class);
+    static LogicalType order() {
+        return LogicalType.fqcn(Order.class);
     }
     
 }
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/mementos/ActionMemento.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/mementos/ActionMemento.java
index 59e3206..61a710b 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/mementos/ActionMemento.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/mementos/ActionMemento.java
@@ -22,8 +22,8 @@ package org.apache.isis.viewer.common.model.mementos;
 import java.io.Serializable;
 import java.util.function.Supplier;
 
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ActionType;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
@@ -93,7 +93,7 @@ public class ActionMemento implements Serializable {
             String nameParmsId,
             SpecificationLoader specificationLoader) {
         
-        val objectSpec = specificationLoader.lookupBySpecIdElseLoad(owningType);
+        val objectSpec = specificationLoader.lookupBySpecIdElseLoad(owningType.asString());
         return objectSpec.getActionElseFail(nameParmsId, actionType);
     }
 
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/menu/MenuUiModelProvider.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/menu/MenuUiModelProvider.java
index 6768409..6287986 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/menu/MenuUiModelProvider.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/menu/MenuUiModelProvider.java
@@ -27,10 +27,10 @@ import javax.inject.Inject;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.DomainServiceLayout;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.val;
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
index 35504c1..7014cdd 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
@@ -24,6 +24,7 @@ import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import org.apache.isis.applib.annotation.DomainServiceLayout;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.facets.object.domainservicelayout.DomainServiceLayoutFacet;
 import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
@@ -33,7 +34,6 @@ import org.apache.isis.core.metamodel.interactions.managed.ManagedProperty;
 import org.apache.isis.core.metamodel.services.ServiceUtil;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.MixedIn;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -193,10 +193,9 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
                 representation.mapPut("serviceId", ServiceUtil.idOfAdapter(objectAdapter));
             } else {
                 rootOidIfAny.ifPresent(rootOid->{
-                    Optional.ofNullable(rootOid.getObjectSpecId())
-                    .map(ObjectSpecId::asString)
-                    .ifPresent(objectSpecIdLiteral->
-                        representation.mapPut("domainType", objectSpecIdLiteral));
+                    Optional.ofNullable(rootOid.getLogicalTypeName())
+                    .ifPresent(domainType->
+                        representation.mapPut("domainType", domainType));
                     representation.mapPut("instanceId", rootOid.getIdentifier());
                 });
             }
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
index 05beeae..b174731 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
@@ -38,12 +38,12 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
diff --git a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java
index ebe44cf..e60aab1 100644
--- a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java
+++ b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java
@@ -36,9 +36,9 @@ import static org.hamcrest.MatcherAssert.assertThat;
 
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 
diff --git a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
index 219fc56..b976178 100644
--- a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
+++ b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asAdapter.java
@@ -45,10 +45,10 @@ import static org.hamcrest.MatcherAssert.assertThat;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.applib.exceptions.recoverable.TextEntryParseException;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 
diff --git a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
index 70b38c7..18cfba1 100644
--- a/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
+++ b/viewers/restfulobjects/rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
@@ -34,9 +34,9 @@ import static org.junit.Assert.assertSame;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
 
 public class JsonValueEncoderTest_asObject {
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
index 80e1990..8474e2c 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainObjectResourceServerside.java
@@ -39,6 +39,7 @@ import javax.ws.rs.core.Response;
 import org.springframework.stereotype.Component;
 
 import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.applib.layout.component.ActionLayoutData;
 import org.apache.isis.applib.layout.component.CollectionLayoutData;
 import org.apache.isis.applib.layout.component.DomainObjectLayoutData;
@@ -60,7 +61,6 @@ import org.apache.isis.core.metamodel.interactions.managed.MemberInteraction.Acc
 import org.apache.isis.core.metamodel.interactions.managed.PropertyInteraction;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects.EntityUtil;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
@@ -114,7 +114,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.BAD_REQUEST, "Body is not a map; got %s", objectRepr);
         }
 
-        final ObjectSpecification domainTypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
+        final ObjectSpecification domainTypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
         if (domainTypeSpec == null) {
             throw RestfulObjectsApplicationException.createWithMessage(HttpStatusCode.BAD_REQUEST, "Could not determine type of domain object to persist (no class with domainType Id of '%s')", domainType);
         }
@@ -343,8 +343,7 @@ public class DomainObjectResourceServerside extends ResourceAbstract implements
             final String domainType,
             final String instanceId) {
         
-        val specId = ObjectSpecId.of(domainType);
-        val objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(specId);
+        val objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
         val gridFacet = objectSpec.getFacet(GridFacet.class);
 
         if(gridFacet == null) {
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainTypeResourceServerside.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainTypeResourceServerside.java
index e84c6bf..cc7ebdc 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainTypeResourceServerside.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/DomainTypeResourceServerside.java
@@ -36,7 +36,6 @@ import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.interaction.session.InteractionTracker;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facets.object.grid.GridFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
@@ -113,7 +112,7 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
         val resourceContext = createResourceContext(
                 RepresentationType.DOMAIN_TYPE, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
 
-        val objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
+        val objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
 
         final DomainTypeReprRenderer renderer = new DomainTypeReprRenderer(resourceContext, null, JsonRepresentation.newMap());
         renderer.with(objectSpec).includesSelf();
@@ -135,7 +134,7 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
         
         val serializationStrategy = resourceContext.getSerializationStrategy();
 
-        val objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
+        val objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
         val gridFacet = objectSpec.getFacet(GridFacet.class);
         
         final Response.ResponseBuilder builder;
@@ -160,7 +159,7 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
         val resourceContext = createResourceContext(
                 RepresentationType.PROPERTY_DESCRIPTION, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
 
-        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
+        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
         if (parentSpec == null) {
             throw RestfulObjectsApplicationException.create(HttpStatusCode.NOT_FOUND);
         }
@@ -188,7 +187,7 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
         val resourceContext = createResourceContext(
                 RepresentationType.COLLECTION_DESCRIPTION, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
 
-        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
+        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
         if (parentSpec == null) {
             throw RestfulObjectsApplicationException.create(HttpStatusCode.NOT_FOUND);
         }
@@ -216,7 +215,7 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
         val resourceContext = createResourceContext(
                 RepresentationType.ACTION_DESCRIPTION, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
 
-        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
+        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
         if (parentSpec == null) {
             throw RestfulObjectsApplicationException.create(HttpStatusCode.NOT_FOUND);
         }
@@ -239,7 +238,7 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
         val resourceContext = createResourceContext(
                 RepresentationType.ACTION_PARAMETER_DESCRIPTION, Where.ANYWHERE, RepresentationService.Intent.NOT_APPLICABLE);
 
-        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
+        val parentSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
         if (parentSpec == null) {
             throw RestfulObjectsApplicationException.create(HttpStatusCode.NOT_FOUND);
         }
@@ -274,8 +273,8 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
 
         final String supertype = domainTypeFor(superTypeStr, argsUrlEncoded, "supertype");
 
-        val domainTypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
-        val supertypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(supertype));
+        val domainTypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
+        val supertypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(supertype);
 
         final TypeActionResultReprRenderer renderer = new TypeActionResultReprRenderer(resourceContext, null, JsonRepresentation.newMap());
 
@@ -306,8 +305,8 @@ public class DomainTypeResourceServerside extends ResourceAbstract implements Do
 
         final String subtype = domainTypeFor(subTypeStr, argsUrlEncoded, "subtype");
 
-        val domainTypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(domainType));
-        val subtypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(ObjectSpecId.of(subtype));
+        val domainTypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(domainType);
+        val subtypeSpec = getSpecificationLoader().lookupBySpecIdElseLoad(subtype);
 
         final TypeActionResultReprRenderer renderer = new TypeActionResultReprRenderer(resourceContext, null, JsonRepresentation.newMap());
 
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java
index 56d776b..0fd6e96 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinkAndLabel.java
@@ -26,10 +26,10 @@ import java.util.List;
 import javax.annotation.Nullable;
 
 import org.apache.isis.applib.annotation.ActionLayout.Position;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.common.model.action.ActionUiMetaModel;
 import org.apache.isis.viewer.wicket.model.common.CommonContextUtils;
@@ -81,7 +81,7 @@ public final class LinkAndLabel extends LinkAndLabelAbstract {
         @NonNull  private final ActionLinkUiComponentFactoryWkt uiComponentFactory;
         @Nullable private final String named;
         @NonNull  private final EntityModel actionHolder;
-        @NonNull  private final ObjectSpecId actionHolderSpecId;
+        @NonNull  private final LogicalType actionHolderLogicalType;
         @NonNull  private final String objectActionId;
         
         private SerializationProxy(LinkAndLabel target) {
@@ -89,14 +89,14 @@ public final class LinkAndLabel extends LinkAndLabelAbstract {
             this.named = target.getNamed();
             this.actionHolder = (EntityModel) target.getActionHolder();
             // make sure we do this without side-effects
-            this.actionHolderSpecId = actionHolder.getTypeOfSpecificationId()
+            this.actionHolderLogicalType = actionHolder.getTypeOfSpecificationId()
                     .orElseThrow(_Exceptions::unexpectedCodeReach); 
             this.objectActionId = target.getObjectAction().getId();
         }
 
         private Object readResolve() {
             val commonContext = CommonContextUtils.getCommonContext();
-            val actionHolderSpec = commonContext.getSpecificationLoader().loadSpecification(actionHolderSpecId);
+            val actionHolderSpec = commonContext.getSpecificationLoader().loadSpecification(actionHolderLogicalType);
             val objectMember = actionHolderSpec
                     .getMember(objectActionId)
                     .orElseThrow(()->
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/CollectionMemento.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/CollectionMemento.java
index a213f37..856c27b 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/CollectionMemento.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/CollectionMemento.java
@@ -21,7 +21,7 @@ package org.apache.isis.viewer.wicket.model.mementos;
 
 import java.io.Serializable;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
@@ -39,8 +39,8 @@ public class CollectionMemento implements Serializable {
     private static ObjectSpecification owningSpecFor(OneToManyAssociation association) {
         
         val specificationLoader = association.getMetaModelContext().getSpecificationLoader();
-        val specId = ObjectSpecId.of(association.getIdentifier().getClassName());
-        return specificationLoader.lookupBySpecIdElseLoad(specId);
+        val logicalType = association.getIdentifier().getLogicalTypeName();
+        return specificationLoader.lookupBySpecIdElseLoad(logicalType);
     }
 
     private final ObjectSpecId owningType;
@@ -103,7 +103,7 @@ public class CollectionMemento implements Serializable {
             ObjectSpecId owningType,
             String id,
             final SpecificationLoader specificationLoader) {
-        return (OneToManyAssociation) specificationLoader.lookupBySpecIdElseLoad(owningType)
+        return (OneToManyAssociation) specificationLoader.lookupBySpecIdElseLoad(owningType.asString())
                 .getAssociationElseFail(id);
     }
 
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/PropertyMemento.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/PropertyMemento.java
index b8f00ed..2f1b866 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/PropertyMemento.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/PropertyMemento.java
@@ -21,7 +21,7 @@ package org.apache.isis.viewer.wicket.model.mementos;
 
 import java.io.Serializable;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
@@ -34,39 +34,37 @@ public class PropertyMemento implements Serializable {
     private static final long serialVersionUID = 1L;
 
     private static ObjectSpecification owningSpecFor(OneToOneAssociation property) {
-        
         val specificationLoader = property.getMetaModelContext().getSpecificationLoader();
-        return specificationLoader.lookupBySpecIdElseLoad(
-                ObjectSpecId.of(property.getIdentifier().getClassName()));
+        return specificationLoader.lookupBySpecIdElseLoad(property.getIdentifier().getLogicalType());
     }
 
-    private final ObjectSpecId owningSpecId;
+    private final LogicalType owningType;
     private final String identifier;
-    private final ObjectSpecId specId;
+    private final LogicalType type;
 
     public PropertyMemento(final OneToOneAssociation property) {
         this(
-                owningSpecFor(property).getSpecId(),
+                owningSpecFor(property).getLogicalType(),
                 property.getIdentifier().getMemberName(),
-                property.getSpecification().getSpecId()
+                property.getSpecification().getLogicalType()
                 );
     }
 
     private PropertyMemento(
-            final ObjectSpecId owningSpecId,
+            final LogicalType owningType,
             final String name,
-            final ObjectSpecId specId) {
-        this.owningSpecId = owningSpecId;
+            final LogicalType type) {
+        this.owningType = owningType;
         this.identifier = name;
-        this.specId = specId;
+        this.type = type;
     }
 
-    public ObjectSpecId getOwningType() {
-        return owningSpecId;
+    public LogicalType getOwningType() {
+        return owningType;
     }
 
-    public ObjectSpecId getType() {
-        return specId;
+    public LogicalType getType() {
+        return type;
     }
 
     public String getIdentifier() {
@@ -74,11 +72,11 @@ public class PropertyMemento implements Serializable {
     }
 
     public OneToOneAssociation getProperty(final SpecificationLoader specificationLoader) {
-        return propertyFor(owningSpecId, identifier, specificationLoader);
+        return propertyFor(owningType, identifier, specificationLoader);
     }
 
     private static OneToOneAssociation propertyFor(
-            ObjectSpecId owningType,
+            LogicalType owningType,
             String identifier,
             final SpecificationLoader specificationLoader) {
         
@@ -124,7 +122,7 @@ public class PropertyMemento implements Serializable {
 
     @Override
     public String toString() {
-        return getOwningType().asString() + "#" + getIdentifier();
+        return getOwningType().getLogicalTypeName() + "#" + getIdentifier();
     }
 
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNodeComparator.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNodeComparator.java
index 87b741d..f7a2f90 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNodeComparator.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNodeComparator.java
@@ -22,7 +22,6 @@ package org.apache.isis.viewer.wicket.model.models;
 import java.util.Comparator;
 
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
 final class BookmarkTreeNodeComparator implements Comparator<BookmarkTreeNode> {
@@ -63,8 +62,7 @@ final class BookmarkTreeNodeComparator implements Comparator<BookmarkTreeNode> {
     }
 
     private String classNameOf(RootOid oid) {
-        ObjectSpecId objectSpecId = oid.getObjectSpecId();
-        return specificationLoader.lookupBySpecIdElseLoad(objectSpecId)
+        return specificationLoader.lookupBySpecIdElseLoad(oid.getLogicalTypeName())
                 .getIdentifier().getClassName();
     }
 
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java
index 5e9d69e..41b3c53 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java
@@ -24,6 +24,8 @@ import java.util.Optional;
 import javax.annotation.Nullable;
 
 import org.apache.isis.applib.annotation.BookmarkPolicy;
+import org.apache.isis.applib.id.LogicalType;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Collections;
@@ -31,7 +33,6 @@ import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
@@ -104,7 +105,7 @@ extends ModelAbstract<ManagedObject> {
         val pojos = adapter.getPojo();
         memento = super.getMementoService()
                 .mementoForPojos(_Casts.uncheckedCast(pojos), getTypeOfSpecificationId()
-                        .orElseGet(()->adapter.getElementSpecification().get().getSpecId()));
+                        .orElseGet(()->adapter.getElementSpecification().get().getLogicalType()));
     }
     
     public final Bookmark asHintingBookmarkIfSupported() {
@@ -128,10 +129,11 @@ extends ModelAbstract<ManagedObject> {
     /**
      * free of side-effects, used for serialization
      * @implNote overriding this must be consistent with {@link #getTypeOfSpecification()}
+     * TODO[2553] rename to getLogicalElementType
      */
-    public Optional<ObjectSpecId> getTypeOfSpecificationId() {
+    public Optional<LogicalType> getTypeOfSpecificationId() {
         return Optional.ofNullable(memento)
-                .map(ObjectMemento::getObjectSpecId);
+                .map(ObjectMemento::getLogicalType);
     }
     
     private transient ObjectSpecification objectSpec;
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java
index e70e686..809cf80 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java
@@ -25,6 +25,7 @@ import java.util.regex.Pattern;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 
 import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.primitives._Ints;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
@@ -33,7 +34,6 @@ import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
index bc8b7c0..dde6c25 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Optional;
 
 import org.apache.isis.applib.annotation.PromptStyle;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -31,7 +32,6 @@ import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
 import org.apache.isis.core.metamodel.facets.object.promptStyle.PromptStyleFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.common.model.feature.ScalarUiModel;
@@ -160,8 +160,9 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
     }
 
     @Override
-    public Optional<ObjectSpecId> getTypeOfSpecificationId() {
-        return Optional.of(getScalarTypeSpec().getSpecId());
+    public Optional<LogicalType> getTypeOfSpecificationId() {
+        return Optional.ofNullable(getScalarTypeSpec())
+                .map(ObjectSpecification::getLogicalType);
     }
     
 
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithMultiPending.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithMultiPending.java
index 03f4470..066084a 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithMultiPending.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModelWithMultiPending.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
 
 import org.apache.wicket.model.Model;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
 
 import lombok.val;
@@ -63,8 +62,8 @@ public interface ScalarModelWithMultiPending extends Serializable {
 
                 @Override
                 public void setMultiPending(final ArrayList<ObjectMemento> pending) {
-                    ObjectSpecId specId = getScalarModel().getTypeOfSpecification().getSpecId();
-                    ObjectMemento adapterMemento = ObjectMemento.wrapMementoList(pending, specId);
+                    val logicalType = getScalarModel().getTypeOfSpecification().getLogicalType();
+                    ObjectMemento adapterMemento = ObjectMemento.wrapMementoList(pending, logicalType);
                     scalarModel.getPendingModel().setObject(adapterMemento);
                 }
 
@@ -108,9 +107,9 @@ public interface ScalarModelWithMultiPending extends Serializable {
                         final ArrayList<ObjectMemento> ownerPending = owner.getMultiPending();
                         if (ownerPending != null) {
                             log.debug("setting to pending: {}", ownerPending.toString());
-                            final ObjectSpecId objectSpecId = ownerScalarModel.getTypeOfSpecification().getSpecId();
+                            val logicalType = ownerScalarModel.getTypeOfSpecification().getLogicalType();
                             ownerScalarModel.memento(
-                                    ObjectMemento.wrapMementoList(adapterMemento, objectSpecId));
+                                    ObjectMemento.wrapMementoList(adapterMemento, logicalType));
                         }
                     }
                 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java
index 709a779..6379bc5 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/bookmarkedpages/BookmarkedPagesPanel.java
@@ -43,8 +43,8 @@ import org.apache.wicket.request.resource.ResourceReference;
 import org.apache.wicket.util.string.Strings;
 
 import org.apache.isis.applib.exceptions.unrecoverable.ObjectNotFoundException;
+import org.apache.isis.applib.id.ObjectSpecId;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.wicket.model.models.BookmarkTreeNode;
 import org.apache.isis.viewer.wicket.model.models.BookmarkedPagesModel;
@@ -164,8 +164,7 @@ public class BookmarkedPagesPanel extends PanelAbstract<BookmarkedPagesModel> {
                     ObjectSpecification objectSpec = null;
                     RootOid oid = node.getOidNoVer();
                     if(oid != null) {
-                        ObjectSpecId objectSpecId = oid.getObjectSpecId();
-                        objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(objectSpecId);
+                        objectSpec = getSpecificationLoader().lookupBySpecIdElseLoad(oid.getLogicalTypeName());
                     }
                     final ResourceReference imageResource = getImageResourceCache().resourceReferenceForSpec(objectSpec);
                     final Image image = new Image(ID_BOOKMARKED_PAGE_ICON, imageResource) {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelectAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelectAbstract.java
index e45def6..9700a17 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelectAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelectAbstract.java
@@ -239,9 +239,9 @@ public abstract class ScalarPanelSelectAbstract extends ScalarPanelAbstract {
                     return;
                 }
                 val memento = proposedValueObjAsList.get(0);
-                val objectSpecId = memento.getObjectSpecId();
+                val logicalType = memento.getLogicalType();
                 proposedValue = ObjectMemento
-                        .wrapMementoList(proposedValueObjAsList, objectSpecId);
+                        .wrapMementoList(proposedValueObjAsList, logicalType);
             } else {
                 proposedValue = (ObjectMemento) proposedValueObj;
             }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/ChoiceExt.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/ChoiceExt.java
index 72f527e..1636f68 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/ChoiceExt.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/ChoiceExt.java
@@ -23,18 +23,18 @@ import org.wicketstuff.select2.Select2Choice;
 import org.wicketstuff.select2.Select2MultiChoice;
 import org.wicketstuff.select2.Settings;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.applib.id.HasLogicalType;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
 
 /**
  * Represents functionality that is common to both {@link Select2Choice} and {@link Select2MultiChoice}, but for
  * which there is no suitable common supertype.
  *
- * Also holds extensions, notable {@link #getSpecId()}.
  */
-public interface ChoiceExt {
+public interface ChoiceExt extends HasLogicalType {
+    
     void setProvider(final ChoiceProvider<ObjectMemento> providerForChoices);
     Settings getSettings();
 
-    ObjectSpecId getSpecId();
+    
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2.java
index cbe531d..ba3101a 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2.java
@@ -109,7 +109,7 @@ public class Select2 implements Serializable {
         } else {
             final Collection<ObjectMemento> modelObject = select2MultiChoice.getModelObject();
 
-            return ObjectMemento.wrapMementoList(modelObject, select2MultiChoice.getSpecId());
+            return ObjectMemento.wrapMementoList(modelObject, select2MultiChoice.getLogicalType());
         }
     }
 
@@ -120,7 +120,7 @@ public class Select2 implements Serializable {
             final IModel<Collection<ObjectMemento>> model = select2MultiChoice.getModel();
             final Collection<ObjectMemento> modelObject = model.getObject();
 
-            final ObjectMemento memento = ObjectMemento.wrapMementoList(modelObject, select2MultiChoice.getSpecId());
+            final ObjectMemento memento = ObjectMemento.wrapMementoList(modelObject, select2MultiChoice.getLogicalType());
             return new IModel<ObjectMemento>() {
                 private static final long serialVersionUID = 1L;
 
@@ -147,7 +147,7 @@ public class Select2 implements Serializable {
             return select2Choice.getConvertedInput();
         } else {
             final Collection<ObjectMemento> convertedInput = select2MultiChoice.getConvertedInput();
-            return ObjectMemento.wrapMementoList(convertedInput, select2MultiChoice.getSpecId());
+            return ObjectMemento.wrapMementoList(convertedInput, select2MultiChoice.getLogicalType());
         }
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2ChoiceExt.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2ChoiceExt.java
index ef6d8cb..ef117b0 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2ChoiceExt.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2ChoiceExt.java
@@ -21,12 +21,16 @@ package org.apache.isis.viewer.wicket.ui.components.widgets.select2;
 import org.apache.wicket.model.IModel;
 import org.wicketstuff.select2.Select2Choice;
 
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.select2.providers.EmptyChoiceProvider;
 
-public class Select2ChoiceExt extends Select2Choice<ObjectMemento> implements ChoiceExt {
+import lombok.Getter;
+
+public class Select2ChoiceExt 
+extends Select2Choice<ObjectMemento> 
+implements ChoiceExt {
     
     private static final long serialVersionUID = 1L;
 
@@ -37,22 +41,18 @@ public class Select2ChoiceExt extends Select2Choice<ObjectMemento> implements Ch
         return new Select2ChoiceExt(id, modelObject, scalarModel);
     }
 
-    private final ObjectSpecId specId;
+    @Getter(onMethod_ = {@Override}) private final LogicalType logicalType;
 
     private Select2ChoiceExt(
             final String id,
             final IModel<ObjectMemento> model,
             final ScalarModel scalarModel) {
         super(id, model, EmptyChoiceProvider.INSTANCE);
-        specId = scalarModel.getTypeOfSpecification().getSpecId();
+        logicalType = scalarModel.getTypeOfSpecification().getLogicalType();
 
         getSettings().setCloseOnSelect(true);
 
         setOutputMarkupPlaceholderTag(true);
     }
 
-    @Override
-    public ObjectSpecId getSpecId() {
-        return specId;
-    }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2MultiChoiceExt.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2MultiChoiceExt.java
index 0abffb1..4a72397 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2MultiChoiceExt.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/Select2MultiChoiceExt.java
@@ -24,17 +24,19 @@ import java.util.Collection;
 import org.apache.wicket.model.IModel;
 import org.wicketstuff.select2.Select2MultiChoice;
 
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.internal.base._Casts;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.select2.providers.EmptyChoiceProvider;
 
+import lombok.Getter;
 import lombok.val;
 
 public class Select2MultiChoiceExt
 extends Select2MultiChoice<ObjectMemento>
-implements ChoiceExt {
+implements 
+    ChoiceExt {
 
     private static final long serialVersionUID = 1L;
 
@@ -46,8 +48,7 @@ implements ChoiceExt {
         return new Select2MultiChoiceExt(id, _Casts.uncheckedCast(modelObject), scalarModel);
     }
 
-    private final ObjectSpecId specId;
-    
+    @Getter(onMethod_ = {@Override}) private final LogicalType logicalType;
 
     Select2MultiChoiceExt(
             final String id,
@@ -55,17 +56,13 @@ implements ChoiceExt {
             final ScalarModel scalarModel) {
         
         super(id, model, EmptyChoiceProvider.INSTANCE);
-        specId = scalarModel.getTypeOfSpecification().getSpecId();
+        logicalType = scalarModel.getTypeOfSpecification().getLogicalType();
 
         getSettings().setCloseOnSelect(true);
 
         setOutputMarkupPlaceholderTag(true);
     }
 
-    @Override
-    public ObjectSpecId getSpecId() {
-        return specId;
-    }
     
     // -- bug in wicket 8.8.0 -------------------------------------------
     
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
index 35c39d5..29909eb 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/select2/providers/ObjectAdapterMementoProviderAbstract.java
@@ -87,14 +87,14 @@ extends ChoiceProvider<ObjectMemento> {
         if (choiceMemento == null) {
             return NULL_PLACEHOLDER;
         }
-        val objectSpecId = choiceMemento.getObjectSpecId();
+        val logicalType = choiceMemento.getLogicalType();
         val spec = getCommonContext().getSpecificationLoader()
-                .lookupBySpecIdElseLoad(objectSpecId);
+                .lookupBySpecIdElseLoad(logicalType);
 
         // support enums that are implementing an interface; only know this late in the day
         // TODO: this is a hack, really should push this deeper so that Encodeable OAMs also prefix themselves with their objectSpecId
         if(spec != null && spec.isEncodeable()) {
-            return objectSpecId.asString() + ":" + choiceMemento.asString();
+            return logicalType.getLogicalTypeName() + ":" + choiceMemento.asString();
         } else {
             return choiceMemento.asString();
         }
diff --git a/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ObjectAdapterMementoProviderForValueChoicesTest.java b/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ObjectAdapterMementoProviderForValueChoicesTest.java
index b897a2e..da99254 100644
--- a/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ObjectAdapterMementoProviderForValueChoicesTest.java
+++ b/viewers/wicket/ui/src/test/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ObjectAdapterMementoProviderForValueChoicesTest.java
@@ -30,9 +30,9 @@ import org.junit.Test;
 
 import static org.hamcrest.CoreMatchers.is;
 
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.internaltestsupport.jmocking.JUnitRuleMockery2;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.context.IsisAppCommonContext;
@@ -41,6 +41,8 @@ import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.select2.providers.ObjectAdapterMementoProviderForValueChoices;
 
+import lombok.val;
+
 public class ObjectAdapterMementoProviderForValueChoicesTest {
 
     @Rule public JUnitRuleMockery2 context = 
@@ -60,10 +62,12 @@ public class ObjectAdapterMementoProviderForValueChoicesTest {
 
     @Before
     public void setUp() throws Exception {
-        final ObjectSpecId fakeSpecId = ObjectSpecId.of("FAKE");
+        final String fakeSpecId = "FAKE";
+        
+        val fakeLocalType = LogicalType.lazy(getClass(), ()->fakeSpecId);
 
-        mockMemento1 = mock(fakeSpecId, "mockMemento1");
-        mockMemento2 = mock(fakeSpecId, "mockMemento2");
+        mockMemento1 = mock(fakeLocalType, "mockMemento1");
+        mockMemento2 = mock(fakeLocalType, "mockMemento2");
 
         mementos = Can.of(mockMemento1, mockMemento2);
         
@@ -78,7 +82,7 @@ public class ObjectAdapterMementoProviderForValueChoicesTest {
             allowing(mockCommonContext).getSpecificationLoader();
             will(returnValue(mockSpecificationLoader));
             
-            allowing(mockSpecificationLoader).lookupBySpecIdElseLoad(fakeSpecId);
+            allowing(mockSpecificationLoader).lookupBySpecIdElseLoad(fakeLocalType);
             will(returnValue(mockSpec));
 
             allowing(mockSpec).isEncodeable();
@@ -99,12 +103,12 @@ public class ObjectAdapterMementoProviderForValueChoicesTest {
     }
 
     private ObjectMemento mock(
-            final ObjectSpecId specId,
+            final LogicalType logicalType,
             final String id) {
         final ObjectMemento mock = context.mock(ObjectMemento.class, id);
         context.checking(new Expectations() {{
-            allowing(mock).getObjectSpecId();
-            will(returnValue(specId));
+            allowing(mock).getLogicalType();
+            will(returnValue(logicalType));
 
             allowing(mock).asString();
             will(returnValue(id));
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java
index f311abf..b5c9c5e 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java
@@ -51,10 +51,9 @@ public class ConverterForObjectAdapter implements IConverter<ManagedObject> {
     @Override
     public ManagedObject convertToObject(final String value, final Locale locale) {
         val rootOid = RootOid.deStringEncoded(value);
-        val objectSpecId = rootOid.getObjectSpecId(); 
         val spec = objectManager.getMetaModelContext()
                 .getSpecificationLoader()
-                .lookupBySpecIdElseLoad(objectSpecId);
+                .lookupBySpecIdElseLoad(rootOid.getLogicalTypeName());
         
         val objectLoadRequest = ObjectLoader.Request.of(spec, rootOid.getIdentifier());
         
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java
index af24d8c..6f046ae 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java
@@ -31,6 +31,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -39,7 +40,6 @@ import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
 import org.apache.isis.core.runtime.memento.ObjectMementoCollection;
@@ -82,7 +82,7 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
         if(mementoAdapter==null) {
             // sonar-ignore-on (fails to detect this as null guard)
             return ManagedObjects.isSpecified(adapter)
-                    ? new ObjectMementoForEmpty(adapter.getSpecification().getSpecId())
+                    ? new ObjectMementoForEmpty(adapter.getSpecification().getLogicalType())
                     : null;
             // sonar-ignore-on
         }
@@ -95,7 +95,7 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
         assertSingleton(paramAdapter);
         val mementoAdapter = ObjectMementoWkt.createOrNull(paramAdapter);
         if(mementoAdapter==null) {
-            return new ObjectMementoForEmpty(paramAdapter.getSpecification().getSpecId());
+            return new ObjectMementoForEmpty(paramAdapter.getSpecification().getLogicalType());
         }
         return ObjectMementoAdapter.of(mementoAdapter);
     }
@@ -111,13 +111,13 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
     }
     
     @Override
-    public ObjectMemento mementoForPojos(Iterable<Object> iterablePojos, ObjectSpecId specId) {
+    public ObjectMemento mementoForPojos(Iterable<Object> iterablePojos, LogicalType logicalType) {
 //        _Probe.errOut("mementoForPojos");
         val listOfMementos = _NullSafe.stream(iterablePojos)
                 .map(pojo->mementoForPojo(pojo))
                 .collect(Collectors.toCollection(ArrayList::new)); // ArrayList is serializable
 
-        return ObjectMementoCollection.of(listOfMementos, specId);
+        return ObjectMementoCollection.of(listOfMementos, logicalType);
     }
 
     @Override
@@ -129,8 +129,8 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
         
         if(memento instanceof ObjectMementoForEmpty) {
             val objectMementoForEmpty = (ObjectMementoForEmpty) memento;
-            val specId = objectMementoForEmpty.getObjectSpecId();
-            val spec = specificationLoader.loadSpecification(specId);
+            val logicalType = objectMementoForEmpty.getLogicalType();
+            val spec = specificationLoader.loadSpecification(logicalType);
             return ManagedObject.empty(spec);
         }
         
@@ -196,10 +196,10 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
         public Bookmark asHintingBookmarkIfSupported() {
             return delegate.asHintingBookmark();
         }
-
+        
         @Override
-        public ObjectSpecId getObjectSpecId() {
-            return delegate.getObjectSpecId();
+        public LogicalType getLogicalType() {
+            return delegate.getLogicalType();
         }
 
         ManagedObject reconstructObject(MetaModelContext mmc) {
@@ -211,6 +211,8 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
             return delegate.toString();
         }
 
+
+
     }
 
 
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoWkt.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoWkt.java
index 6ad0084..260416e 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoWkt.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoWkt.java
@@ -26,6 +26,8 @@ import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
 
+import org.apache.isis.applib.id.HasLogicalType;
+import org.apache.isis.applib.id.LogicalType;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.hint.HintIdProvider;
 import org.apache.isis.commons.internal.base._NullSafe;
@@ -37,20 +39,20 @@ import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
-import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
 import lombok.AccessLevel;
+import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.NonNull;
 import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Log4j2
-final class ObjectMementoWkt implements Serializable {
+final class ObjectMementoWkt implements HasLogicalType, Serializable {
 
     private static final long serialVersionUID = 1L;
 
@@ -178,8 +180,8 @@ final class ObjectMementoWkt implements Serializable {
                     ObjectMementoWkt memento,
                     MetaModelContext mmc) {
 
-                ObjectSpecId specId = memento.objectSpecId;
-                ObjectSpecification objectSpec = mmc.getSpecificationLoader().lookupBySpecIdElseLoad(specId);
+                ObjectSpecification objectSpec = mmc.getSpecificationLoader()
+                        .lookupBySpecIdElseLoad(memento.logicalType);
                 EncodableFacet encodableFacet = objectSpec.getFacet(EncodableFacet.class);
                 return encodableFacet.fromEncodedString(memento.encodableValue);
             }
@@ -220,7 +222,8 @@ final class ObjectMementoWkt implements Serializable {
                     MetaModelContext mmc) {
 
                 if(_NullSafe.isEmpty(memento.persistentOidStr)) {
-                    throw _Exceptions.illegalArgument("need an id to lookup an object specId=%s", memento.objectSpecId);
+                    throw _Exceptions.illegalArgument(
+                            "need an id to lookup an object, got logical-type %s", memento.logicalType);
                 }
 
                 RootOid rootOid = Oid.unmarshaller().unmarshal(memento.persistentOidStr, RootOid.class);
@@ -277,9 +280,8 @@ final class ObjectMementoWkt implements Serializable {
             public ManagedObject recreateObject(
                     ObjectMementoWkt memento,
                     MetaModelContext mmc) {
-
-                ObjectSpecId specId = memento.objectSpecId;
-                ObjectSpecification spec = mmc.getSpecificationLoader().lookupBySpecIdElseLoad(specId);
+                ObjectSpecification spec = mmc.getSpecificationLoader()
+                        .lookupBySpecIdElseLoad(memento.logicalType);
                 return mmc.getObjectManager().getObjectSerializer()
                         .deserialize(spec, memento.serializedObject);
             }
@@ -289,7 +291,7 @@ final class ObjectMementoWkt implements Serializable {
                     ObjectMementoWkt memento,
                     ObjectMementoWkt otherMemento) {
                 return otherMemento.recreateStrategy == SERIALIZABLE
-                        && Objects.equals(memento.objectSpecId, otherMemento.objectSpecId)
+                        && Objects.equals(memento.logicalType, otherMemento.logicalType)
                         && Objects.equals(memento.serializedObject, otherMemento.serializedObject);
             }
 
@@ -300,7 +302,7 @@ final class ObjectMementoWkt implements Serializable {
 
             @Override
             public String toString(ObjectMementoWkt memento) {
-                return "ObjectMementoWkt {SERIALIZABLE " + memento.objectSpecId + "}";
+                return "ObjectMementoWkt {SERIALIZABLE " + memento.getLogicalTypeName() + "}";
             }
 
             @Override
@@ -331,7 +333,7 @@ final class ObjectMementoWkt implements Serializable {
 
 
     private final Cardinality cardinality;
-    private final ObjectSpecId objectSpecId;
+    @Getter(onMethod_ = {@Override}) private final LogicalType logicalType;
 
     /**
      * Populated only if {@link #getCardinality() sort} is {@link Cardinality#SCALAR scalar}
@@ -388,48 +390,48 @@ final class ObjectMementoWkt implements Serializable {
 
     private ObjectMementoWkt(
             ArrayList<ObjectMementoWkt> list,
-            ObjectSpecId objectSpecId) {
+            LogicalType logicalType) {
 
         this.cardinality = Cardinality.VECTOR;
         this.list = list;
-        this.objectSpecId = objectSpecId;
+        this.logicalType = logicalType;
     }
 
     private ObjectMementoWkt(RootOid rootOid, SpecificationLoader specificationLoader) {
 
         // -- // TODO[2112] do we ever need to create ENCODEABLE here?
-        val specId = rootOid.getObjectSpecId();
-        val spec = specificationLoader.lookupBySpecIdElseLoad(specId);
-        if(spec!=null && spec.isEncodeable()) {
-            this.cardinality = Cardinality.SCALAR;
-            this.objectSpecId = specId;
+        val logicalTypeName = rootOid.getLogicalTypeName();
+        val spec = specificationLoader.lookupBySpecIdElseLoad(logicalTypeName);
+        if(spec==null) {
+            throw _Exceptions.unrecoverableFormatted("cannot recreate spec from logicalTypeName %s", logicalTypeName);
+        }
+        
+        this.cardinality = Cardinality.SCALAR;
+        this.logicalType = spec.getLogicalType();
+        
+        if(spec.isEncodeable()) {
             this.encodableValue = rootOid.getIdentifier();
             this.recreateStrategy = RecreateStrategy.ENCODEABLE;
             return;
         }
-        // -- //
-
-        this.cardinality = Cardinality.SCALAR;
 
         this.persistentOidStr = rootOid.enString();
-
         requires(persistentOidStr, "persistentOidStr");
 
         this.bookmark = rootOid.asBookmark();
-        this.objectSpecId = rootOid.getObjectSpecId();
         this.recreateStrategy = RecreateStrategy.LOOKUP;
     }
 
     private ObjectMementoWkt(@NonNull final ManagedObject adapter) {
         this.cardinality = Cardinality.SCALAR;
         val spec = adapter.getSpecification();
-        objectSpecId = spec.getSpecId();
+        this.logicalType = spec.getLogicalType();
         init(adapter);
     }
 
-    private ObjectMementoWkt(ObjectSpecId specId, String encodableValue) {
+    private ObjectMementoWkt(LogicalType logicalType, String encodableValue) {
         this.cardinality = Cardinality.SCALAR;
-        this.objectSpecId = specId;
+        this.logicalType = logicalType;
         this.encodableValue = encodableValue;
         this.recreateStrategy = RecreateStrategy.ENCODEABLE;
     }
@@ -488,7 +490,7 @@ final class ObjectMementoWkt implements Serializable {
         val bookmark = asBookmark();
         return hintId != null && bookmark != null
                 ? bookmark.withHintId(hintId)
-                        : bookmark;
+                : bookmark;
     }
 
     /**
@@ -504,7 +506,7 @@ final class ObjectMementoWkt implements Serializable {
     ManagedObject reconstructObject(MetaModelContext mmc) {
 
         val specificationLoader = mmc.getSpecificationLoader();
-        val spec = specificationLoader.loadSpecification(objectSpecId);
+        val spec = specificationLoader.lookupBySpecIdElseLoad(logicalType);
         if(spec==null) {
             // eg. ill-formed request
             return null;
@@ -512,16 +514,12 @@ final class ObjectMementoWkt implements Serializable {
 
         // intercept when managed by IoCC
         if(spec.getBeanSort().isManagedBean()) {
-            return spec.getMetaModelContext().lookupServiceAdapterById(objectSpecId.asString());
+            return spec.getMetaModelContext().lookupServiceAdapterById(getLogicalTypeName());
         }
 
         return cardinality.asAdapter(this, mmc);
     }
 
-    ObjectSpecId getObjectSpecId() {
-        return objectSpecId;
-    }
-
     @Override
     public int hashCode() {
         return cardinality.hashCode(this);