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/05/06 19:15:19 UTC

[isis] branch 2648-wkt.coll.model created (now da9a3fd)

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

ahuber pushed a change to branch 2648-wkt.coll.model
in repository https://gitbox.apache.org/repos/asf/isis.git.


      at da9a3fd  ISIS-2648: split the entity coll. model into 3 concrete types

This branch includes the following new commits:

     new da9a3fd  ISIS-2648: split the entity coll. model into 3 concrete types

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[isis] 01/01: ISIS-2648: split the entity coll. model into 3 concrete types

Posted by ah...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ahuber pushed a commit to branch 2648-wkt.coll.model
in repository https://gitbox.apache.org/repos/asf/isis.git

commit da9a3fd46bfb24875658c7687a4578a1c822b4af
Author: Andi Huber <ah...@apache.org>
AuthorDate: Thu May 6 21:14:58 2021 +0200

    ISIS-2648: split the entity coll. model into 3 concrete types
---
 .../metamodel/facets/object/paged/PagedFacet.java  |  16 +
 .../interactions/managed/ManagedProperty.java      |  64 +--
 .../core/metamodel/spec/feature/ObjectAction.java  |  62 +--
 .../isis/core/runtime/memento/ObjectMemento.java   |  18 +-
 .../ui/components/ScalarPanelAbstractLegacy.java   |  26 +-
 .../viewer/wicket/model/links/LinkAndLabel.java    |  39 +-
 .../viewer/wicket/model/links/LinksProvider.java   |   5 +-
 .../wicket/model/links/ListOfLinksModel.java       |   9 +-
 .../wicket/model/models/EntityCollectionModel.java | 558 +++------------------
 .../models/EntityCollectionModelAbstract.java      | 105 ++++
 .../model/models/EntityCollectionModelDummy.java   |  93 ++++
 .../models/EntityCollectionModelParented.java      | 191 +++++++
 .../models/EntityCollectionModelStandalone.java    | 133 +++++
 .../viewer/wicket/model/models/ScalarModel.java    |  59 ++-
 ...odel.java => _EntityCollectionModelLegacy.java} |  64 ++-
 .../actionresponse/ActionResultResponseType.java   |  23 +-
 .../AdditionalLinksAsDropDownPanel.java            |   5 +-
 .../AdditionalLinksAsListInlinePanel.java          |   5 +-
 .../entityactions/AdditionalLinksPanel.java        |  33 +-
 .../actionmenu/entityactions/LinkAndLabelUtil.java |  43 +-
 .../collection/AssociatedWithActionsHelper.java    |  70 ---
 .../ui/components/collection/CollectionPanel.java  |  43 +-
 .../selector/CollectionSelectorHelper.java         |  94 ++--
 .../selector/CollectionSelectorPanel.java          |  11 +-
 .../CollectionContentsAsAjaxTablePanel.java        |   8 +-
 .../columns/ObjectAdapterPropertyColumn.java       |  13 +-
 .../columns/ObjectAdapterTitleColumn.java          |  42 +-
 .../CollectionContentsMultipleViewsPanel.java      |  30 +-
 .../entity/collection/EntityCollectionPanel.java   |  44 +-
 .../components/entity/fieldset/PropertyGroup.java  |  33 +-
 .../entity/header/EntityHeaderPanel.java           |  21 +-
 .../wicket/ui/components/layout/bs3/col/Col.java   |  37 +-
 .../ui/components/scalars/ScalarPanelAbstract.java |  88 ++--
 .../StandaloneCollectionPanel.java                 |  17 +-
 .../StandaloneCollectionPanelFactory.java          |  10 +-
 .../StandaloneCollectionPage.java                  |  18 +-
 36 files changed, 1063 insertions(+), 1067 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/paged/PagedFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/paged/PagedFacet.java
index 64baa31..4efc72e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/paged/PagedFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/paged/PagedFacet.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.metamodel.facets.object.paged;
 
+import javax.annotation.Nullable;
+
 import org.apache.isis.core.metamodel.facetapi.Facet;
 
 /**
@@ -28,4 +30,18 @@ public interface PagedFacet extends Facet {
 
     int value();
 
+    /**
+     * Returns the page-size as held by given {@code pagedFacet} if present, otherwise
+     * falls back to {@code defaultPageSize}.
+     * @param pagedFacet - null-able
+     * @param defaultPageSize
+     */
+    static int pageSizeOrDefault(
+            final @Nullable PagedFacet pagedFacet,
+            final int defaultPageSize) {
+        return pagedFacet != null
+                ? pagedFacet.value()
+                : defaultPageSize;
+    }
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
index 7e1aa9d..37e704f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
@@ -38,31 +38,31 @@ import lombok.NonNull;
 import lombok.val;
 
 public final class ManagedProperty extends ManagedMember {
-    
+
     // -- FACTORIES
-    
+
     public static final ManagedProperty of(
-            final @NonNull ManagedObject owner, 
+            final @NonNull ManagedObject owner,
             final @NonNull OneToOneAssociation property,
             final @NonNull Where where) {
         return new ManagedProperty(owner, property, where);
     }
-    
+
     public static final Optional<ManagedProperty> lookupProperty(
             @NonNull final ManagedObject owner,
-            @NonNull final String memberId, 
+            @NonNull final String memberId,
             @NonNull final Where where) {
-        
+
         return ManagedMember.<OneToOneAssociation>lookup(owner, MemberType.PROPERTY, memberId)
         .map(objectAction -> of(owner, objectAction, where));
     }
-    
+
     // -- IMPLEMENTATION
-    
+
     @Getter private final OneToOneAssociation property;
-    
+
     private ManagedProperty(
-            final @NonNull ManagedObject owner, 
+            final @NonNull ManagedObject owner,
             final @NonNull OneToOneAssociation property,
             final @NonNull Where where) {
         super(owner, where);
@@ -79,39 +79,39 @@ public final class ManagedProperty extends ManagedMember {
     public MemberType getMemberType() {
         return MemberType.PROPERTY;
     }
-    
+
     public Can<ObjectAction> getAssociatedActions() {
-        return Can.ofCollection(ObjectAction.Util.findForAssociation(getOwner(), getProperty()));
+        return Can.ofStream(ObjectAction.Util.findForAssociation(getOwner(), getProperty()));
     }
-    
+
     // -- INTERACTION
-    
+
     public Optional<InteractionVeto> checkValidity(ManagedObject proposedNewValue) {
         try {
-            
-            val validityConsent = 
+
+            val validityConsent =
                     property.isAssociationValid(getOwner(), proposedNewValue, InteractionInitiatedBy.USER);
-            
+
             return validityConsent.isVetoed()
-                    ? Optional.of(InteractionVeto.invalid(validityConsent)) 
+                    ? Optional.of(InteractionVeto.invalid(validityConsent))
                     : Optional.empty();
-            
+
         } catch (final Exception ex) {
-            
+
             return Optional.of(InteractionVeto
                     .invalid(
                             new Veto(ex.getLocalizedMessage())));
-            
+
         }
     }
-    
-    
+
+
     /**
      * @param proposedNewValue
      * @return non-empty if the interaction is not valid for given {@code proposedNewValue}
      */
     public Optional<InteractionVeto> modifyProperty(@Nullable ManagedObject proposedNewValue) {
-            
+
         val interactionVeto = checkValidity(proposedNewValue);
         if(interactionVeto.isPresent()) {
             return interactionVeto;
@@ -131,14 +131,14 @@ public final class ManagedProperty extends ManagedMember {
     private ManagedObject reassessPropertyValue() {
         val property = getProperty();
         val owner = getOwner();
-        
-        return property.isVisible(owner, InteractionInitiatedBy.FRAMEWORK, getWhere()).isAllowed() 
+
+        return property.isVisible(owner, InteractionInitiatedBy.FRAMEWORK, getWhere()).isAllowed()
                 && property.isVisible(owner, InteractionInitiatedBy.USER, getWhere()).isAllowed()
             ? property.get(owner, InteractionInitiatedBy.USER)
             : ManagedObject.empty(property.getSpecification());
     }
-    
-    
+
+
     // -- NEGOTIATION
 
     public PropertyNegotiationModel startNegotiation() {
@@ -146,9 +146,9 @@ public final class ManagedProperty extends ManagedMember {
     }
 
     // -- BINDING
-    
+
     @NonNull private final LazyObservable<ManagedObject> observablePropValue;
-    
+
     public Observable<ManagedObject> getValue() {
         return observablePropValue;
     }
@@ -156,7 +156,7 @@ public final class ManagedProperty extends ManagedMember {
     public ManagedObject getPropertyValue() {
         return getValue().getValue();
     }
-    
-    
+
+
 }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index 5a42745..79fc27d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@ -17,8 +17,6 @@
 
 package org.apache.isis.core.metamodel.spec.feature;
 
-import java.util.Collections;
-import java.util.List;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
@@ -37,12 +35,10 @@ import org.apache.isis.applib.value.Clob;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.collections.CanVector;
 import org.apache.isis.commons.internal.base._Strings;
-import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Sets;
 import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.consent.InteractionResultSet;
-import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.facets.actions.action.associateWith.AssociatedWithFacet;
 import org.apache.isis.core.metamodel.facets.actions.position.ActionPositionFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
@@ -268,13 +264,6 @@ public interface ObjectAction extends ObjectMember {
 
     public static final class Util {
 
-        private Util() {
-        }
-
-        private static boolean isPrototyping(ManagedObject adapter) {
-            return MetaModelContext.from(adapter).getSystemEnvironment().isPrototyping();
-        }
-
         public static String nameFor(final ObjectAction objAction) {
             final String actionName = objAction.getName();
             if (actionName != null) {
@@ -343,60 +332,28 @@ public interface ObjectAction extends ObjectMember {
             return cssClassFacet != null ? cssClassFacet.cssClass(objectAdapter) : null;
         }
 
-        public static List<ObjectAction> findTopLevel(
+        public static Stream<ObjectAction> streamTopLevelActions(
                 final ManagedObject adapter) {
 
-            val topLevelActions = _Lists.<ObjectAction>newArrayList();
-
-            addTopLevelActions(adapter, ActionType.USER, topLevelActions);
-            if(isPrototyping(adapter)) {
-                addTopLevelActions(adapter, ActionType.PROTOTYPE, topLevelActions);
-            }
-            return topLevelActions;
-        }
-
-        static void addTopLevelActions(
-                final ManagedObject adapter,
-                final ActionType actionType,
-                final List<ObjectAction> topLevelActions) {
-
             val spec = adapter.getSpecification();
 
-            spec.streamDeclaredActions(actionType, MixedIn.INCLUDED)
+            return spec.streamRuntimeActions(MixedIn.INCLUDED)
             .filter(ObjectAction.Predicates.memberOrderNotAssociationOf(spec))
             .filter(ObjectAction.Predicates.dynamicallyVisible(adapter,
                     InteractionInitiatedBy.USER, Where.ANYWHERE))
-            .filter(ObjectAction.Predicates.excludeWizardActions(spec))
-            .forEach(topLevelActions::add);
-
+            .filter(ObjectAction.Predicates.excludeWizardActions(spec));
         }
 
-        public static List<ObjectAction> findForAssociation(
+        public static Stream<ObjectAction> findForAssociation(
                 final ManagedObject adapter,
                 final ObjectAssociation association) {
 
-            val associatedActions = _Lists.<ObjectAction>newArrayList();
-
-            addActions(adapter, ActionType.USER, association, associatedActions);
-            if(isPrototyping(adapter)) {
-                addActions(adapter, ActionType.PROTOTYPE, association, associatedActions);
-            }
-
-            Collections.sort(associatedActions, Comparators.byMemberOrderSequence(false));
-            return associatedActions;
-        }
-
-        static void addActions(
-                final ManagedObject adapter,
-                final ActionType type,
-                final ObjectAssociation association, final List<ObjectAction> associatedActions) {
-
-            val objectSpecification = adapter.getSpecification();
+            val spec = adapter.getSpecification();
 
-            objectSpecification.streamDeclaredActions(type, MixedIn.INCLUDED)
+            return spec.streamRuntimeActions(MixedIn.INCLUDED)
             .filter(ObjectAction.Predicates.actionIsAssociatedWith(association))
-            .filter(ObjectAction.Predicates.excludeWizardActions(objectSpecification))
-            .forEach(associatedActions::add);
+            .filter(ObjectAction.Predicates.excludeWizardActions(spec))
+            .sorted(Comparators.byMemberOrderSequence(false));
         }
 
         public static PromptStyle promptStyleFor(final ObjectAction objectAction) {
@@ -434,9 +391,6 @@ public interface ObjectAction extends ObjectMember {
 
     public static final class Predicates {
 
-        private Predicates() {
-        }
-
         public static Predicate<ObjectAction> associatedWith(final ObjectAssociation objectAssociation) {
             return new AssociatedWith(objectAssociation);
         }
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 56b8071..df5a7bd 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
@@ -36,27 +36,27 @@ import org.apache.isis.commons.internal.collections._Lists;
 public interface ObjectMemento extends HasLogicalType, Serializable {
 
     String asString();
-    
+
     /**
-     * Returns a bookmark only if 
+     * Returns a bookmark only if
      * {@link org.apache.isis.viewer.wicket.viewer.services.mementos.ObjectMementoWkt.RecreateStrategy#LOOKUP} and
      * {@link #getCardinality() sort} is {@link Cardinality#SCALAR scalar}.
-     * Returns {@code null} otherwise. 
+     * Returns {@code null} otherwise.
      */
     Bookmark asBookmarkIfSupported();
 
     /**
-     * Returns a bookmark only if 
+     * Returns a bookmark only if
      * {@link org.apache.isis.viewer.wicket.viewer.services.mementos.ObjectMementoWkt.RecreateStrategy#LOOKUP} and
      * {@link #getCardinality() sort} is {@link Cardinality#SCALAR scalar}.
-     * Returns {@code null} otherwise. 
+     * Returns {@code null} otherwise.
      */
     Bookmark asHintingBookmarkIfSupported();
-    
+
     // -- FACTORIES
 
     static ObjectMemento wrapMementoList(
-            Collection<ObjectMemento> container, 
+            Collection<ObjectMemento> container,
             LogicalType logicalType) {
 
         // ArrayList is serializable
@@ -76,6 +76,6 @@ public interface ObjectMemento extends HasLogicalType, Serializable {
         }
         return Optional.ofNullable(((ObjectMementoCollection)memento).unwrapList());
     }
-    
-    
+
+
 }
diff --git a/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/ScalarPanelAbstractLegacy.java b/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/ScalarPanelAbstractLegacy.java
index d9be8ce..85bf2db 100644
--- a/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/ScalarPanelAbstractLegacy.java
+++ b/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/ScalarPanelAbstractLegacy.java
@@ -32,6 +32,7 @@ import org.apache.wicket.model.Model;
 
 import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacet;
@@ -60,8 +61,8 @@ import lombok.val;
  *     It is however still used by some wicket addons (specifically, pdfjs).
  * </p>
  */
-abstract class ScalarPanelAbstractLegacy 
-extends PanelAbstract<ManagedObject, ScalarModel> 
+abstract class ScalarPanelAbstractLegacy
+extends PanelAbstract<ManagedObject, ScalarModel>
 implements ScalarModelProvider {
 
     private static final long serialVersionUID = 1L;
@@ -186,7 +187,7 @@ implements ScalarModelProvider {
         } else {
             if (scalarModel.isViewMode()) {
                 onBeforeRenderWhenViewMode();
-            } else {        
+            } else {
                 onBeforeRenderWhenEnabled();
             }
         }
@@ -310,16 +311,23 @@ implements ScalarModelProvider {
      * @param markupContainer The form group element
      * @param entityActionLinks
      */
-    protected void addPositioningCssTo(final MarkupContainer markupContainer, final List<LinkAndLabel> entityActionLinks) {
+    protected void addPositioningCssTo(
+            final MarkupContainer markupContainer,
+            final Can<LinkAndLabel> entityActionLinks) {
         CssClassAppender.appendCssClassTo(markupContainer, determinePropParamLayoutCss(getModel()));
         CssClassAppender.appendCssClassTo(markupContainer, determineActionLayoutPositioningCss(entityActionLinks));
     }
 
-    protected void addEntityActionLinksBelowAndRight(final MarkupContainer labelIfRegular, final List<LinkAndLabel> entityActions) {
-        final List<LinkAndLabel> entityActionsBelow = LinkAndLabel.positioned(entityActions, ActionLayout.Position.BELOW);
+    protected void addEntityActionLinksBelowAndRight(
+            final MarkupContainer labelIfRegular,
+            final Can<LinkAndLabel> entityActions) {
+
+        final Can<LinkAndLabel> entityActionsBelow = entityActions
+                .filter(LinkAndLabel.positioned(ActionLayout.Position.BELOW));
         AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ASSOCIATED_ACTION_LINKS_BELOW, entityActionsBelow, AdditionalLinksPanel.Style.INLINE_LIST);
 
-        final List<LinkAndLabel> entityActionsRight = LinkAndLabel.positioned(entityActions, ActionLayout.Position.RIGHT);
+        final Can<LinkAndLabel> entityActionsRight = entityActions
+                .filter(LinkAndLabel.positioned(ActionLayout.Position.RIGHT));
         AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ASSOCIATED_ACTION_LINKS_RIGHT, entityActionsRight, AdditionalLinksPanel.Style.DROPDOWN);
     }
 
@@ -342,12 +350,12 @@ implements ScalarModelProvider {
         return "label-left";
     }
 
-    private static String determineActionLayoutPositioningCss(List<LinkAndLabel> entityActionLinks) {
+    private static String determineActionLayoutPositioningCss(Can<LinkAndLabel> entityActionLinks) {
         boolean actionsPositionedOnRight = hasActionsPositionedOn(entityActionLinks, ActionLayout.Position.RIGHT);
         return actionsPositionedOnRight ? "actions-right" : null;
     }
 
-    private static boolean hasActionsPositionedOn(final List<LinkAndLabel> entityActionLinks, final ActionLayout.Position position) {
+    private static boolean hasActionsPositionedOn(final Can<LinkAndLabel> entityActionLinks, final ActionLayout.Position position) {
         for (LinkAndLabel entityActionLink : entityActionLinks) {
             if(entityActionLink.getActionUiMetaModel().getPosition() == position) {
                 return true;
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 3453823..81b2df3 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
@@ -21,14 +21,17 @@ package org.apache.isis.viewer.wicket.model.links;
 import java.io.InvalidObjectException;
 import java.io.ObjectInputStream;
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 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.collections.Can;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.common.model.action.ActionUiMetaModel;
@@ -41,7 +44,7 @@ import lombok.val;
 public final class LinkAndLabel extends LinkAndLabelAbstract {
 
     private static final long serialVersionUID = 1L;
-    
+
     public static LinkAndLabel of(
             final ActionLinkUiComponentFactoryWkt uiComponentFactory,
             final String named,
@@ -49,7 +52,7 @@ public final class LinkAndLabel extends LinkAndLabelAbstract {
             final ObjectAction objectAction) {
         return new LinkAndLabel(uiComponentFactory, named, actionHolderModel, objectAction);
     }
-    
+
     private LinkAndLabel(
             final ActionLinkUiComponentFactoryWkt uiComponentFactory,
             final String named,
@@ -58,14 +61,22 @@ public final class LinkAndLabel extends LinkAndLabelAbstract {
         super(uiComponentFactory, named, actionHolderModel, objectAction);
     }
 
-    public static List<LinkAndLabel> positioned(List<LinkAndLabel> list, Position pos) {
-        return _Lists.filter(list, ActionUiMetaModel.positioned(pos, LinkAndLabel::getActionUiMetaModel));
+    public static Can<LinkAndLabel> positioned(Position pos, Stream<LinkAndLabel> stream) {
+        return stream.filter(LinkAndLabel.positioned(pos))
+        .collect(Can.toCan());
+        //.collect(Collectors.toCollection(ArrayList::new));
+    }
+
+    public static Predicate<LinkAndLabel> positioned(Position pos) {
+        return ActionUiMetaModel.positioned(pos, LinkAndLabel::getActionUiMetaModel);
     }
 
-    public static List<LinkAndLabel> recoverFromIncompleteDeserialization(List<SerializationProxy> list) {
-        return _Casts.uncheckedCast(_Lists.map(list, SerializationProxy::readResolve));
+    public static List<LinkAndLabel> recoverFromIncompleteDeserialization(List<SerializationProxy> proxies) {
+        return proxies.stream()
+                .map(SerializationProxy::readResolve)
+                .collect(Collectors.toCollection(ArrayList::new));
     }
-    
+
     // -- SERIALIZATION PROXY
 
     private Object writeReplace() {
@@ -83,18 +94,18 @@ public final class LinkAndLabel extends LinkAndLabelAbstract {
         @NonNull  private final EntityModel actionHolder;
         @NonNull  private final LogicalType actionHolderLogicalType;
         @NonNull  private final String objectActionId;
-        
+
         private SerializationProxy(LinkAndLabel target) {
-            this.uiComponentFactory = (ActionLinkUiComponentFactoryWkt)target.uiComponentFactory;
+            this.uiComponentFactory = target.uiComponentFactory;
             this.named = target.getNamed();
             this.actionHolder = (EntityModel) target.getActionHolder();
             // make sure we do this without side-effects
             this.actionHolderLogicalType = actionHolder.getLogicalElementType()
-                    .orElseThrow(_Exceptions::unexpectedCodeReach); 
+                    .orElseThrow(_Exceptions::unexpectedCodeReach);
             this.objectActionId = target.getObjectAction().getId();
         }
 
-        private Object readResolve() {
+        private LinkAndLabel readResolve() {
             val commonContext = CommonContextUtils.getCommonContext();
             val objectMember = commonContext.getSpecificationLoader()
             .specForLogicalType(actionHolderLogicalType)
@@ -104,5 +115,5 @@ public final class LinkAndLabel extends LinkAndLabelAbstract {
             return new LinkAndLabel(uiComponentFactory, named, actionHolder, (ObjectAction) objectMember);
         }
     }
-    
+
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinksProvider.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinksProvider.java
index c65a220..bd1ed0e 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinksProvider.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/LinksProvider.java
@@ -18,10 +18,9 @@
  */
 package org.apache.isis.viewer.wicket.model.links;
 
-import java.util.List;
-
 import org.apache.wicket.markup.html.link.Link;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
 
 /**
@@ -29,5 +28,5 @@ import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
  * additional list of {@link Link}s to be rendered.
  */
 public interface LinksProvider {
-    List<LinkAndLabel> getLinks();
+    Can<LinkAndLabel> getLinks();
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/ListOfLinksModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/ListOfLinksModel.java
index 5337ecb..ec45dec 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/ListOfLinksModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/links/ListOfLinksModel.java
@@ -22,8 +22,8 @@ import java.util.List;
 
 import org.apache.wicket.model.LoadableDetachableModel;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Casts;
-import org.apache.isis.commons.internal.collections._Lists;
 
 import lombok.val;
 
@@ -33,9 +33,8 @@ public class ListOfLinksModel extends LoadableDetachableModel<List<LinkAndLabel>
 
     private List<LinkAndLabel> links;
 
-    public ListOfLinksModel(List<LinkAndLabel> links) {
-        // copy, in case supplied list is a non-serializable guava list using lazy evaluation;
-        this.links = _Lists.newArrayList(links);
+    public ListOfLinksModel(Can<LinkAndLabel> links) {
+        this.links = links.toList();
     }
 
     @Override
@@ -60,7 +59,7 @@ public class ListOfLinksModel extends LoadableDetachableModel<List<LinkAndLabel>
         if(links.size()>0) {
             if(! (links.get(0) instanceof LinkAndLabel)) {
                 return links = LinkAndLabel.recoverFromIncompleteDeserialization(_Casts.uncheckedCast(links));
-            } 
+            }
         }
         return links;
     }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
index 66ea614..95492b4 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
@@ -16,141 +16,38 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-
 package org.apache.isis.viewer.wicket.model.models;
 
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import javax.annotation.Nullable;
 
-import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
 
 import org.apache.isis.applib.Identifier;
-import org.apache.isis.applib.layout.component.CollectionLayoutData;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.commons.internal.collections._Maps;
-import org.apache.isis.commons.internal.factory._InstanceUtil;
-import org.apache.isis.core.metamodel.commons.ClassExtensions;
-import org.apache.isis.core.metamodel.commons.ClassUtil;
-import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
-import org.apache.isis.core.metamodel.facets.collections.sortedby.SortedByFacet;
-import org.apache.isis.core.metamodel.facets.object.paged.PagedFacet;
-import org.apache.isis.core.metamodel.facets.object.plural.PluralFacet;
+import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 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.OneToManyAssociation;
-import org.apache.isis.core.runtime.context.IsisAppCommonContext;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.runtime.context.IsisAppCommonContext.HasCommonContext;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
-import org.apache.isis.core.runtime.memento.ObjectMementoService;
-import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
-import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.links.LinksProvider;
-import org.apache.isis.viewer.wicket.model.mementos.CollectionMemento;
-
-import static org.apache.isis.commons.internal.base._NullSafe.stream;
 
 import lombok.Getter;
-import lombok.val;
-
-/**
- * Model representing a collection of entities, either {@link Variant#STANDALONE
- * standalone} (eg result of invoking an action) or {@link Variant#PARENTED
- * parented} (contents of the collection of an entity).
- *
- * <p>
- * So that the model is {@link Serializable}, the {@link ManagedObject}s within
- * the collection are stored as {@link ObjectMemento}s.
- */
-public class EntityCollectionModel
-extends ModelAbstract<List<ManagedObject>>
-implements
-    LinksProvider,
-    UiHintContainer {
-
-    private static final long serialVersionUID = 1L;
-
-    private static final int PAGE_SIZE_DEFAULT_FOR_PARENTED = 12;
-    private static final int PAGE_SIZE_DEFAULT_FOR_STANDALONE = 25;
-
-    // -- FACTORIES
-
-    public static EntityCollectionModel createParented(EntityModel entityModel) {
-
-        val oneToManyAssociation = collectionFor(entityModel);
-        val typeOf = forName(oneToManyAssociation.getSpecification());
-        final int pageSize = pageSize(oneToManyAssociation.getFacet(PagedFacet.class), PAGE_SIZE_DEFAULT_FOR_PARENTED);
-        val sortedByFacet = oneToManyAssociation.getFacet(SortedByFacet.class);
-
-        val entityCollectionModel = new EntityCollectionModel(
-                entityModel.getCommonContext(),
-                Variant.PARENTED,
-                oneToManyAssociation.getIdentifier(),
-                entityModel,
-                typeOf,
-                pageSize);
-        entityCollectionModel.collectionMemento = new CollectionMemento(oneToManyAssociation);
-        entityCollectionModel.sortedBy = (sortedByFacet != null)
-                ? sortedByFacet.value()
-                : null;
-        return entityCollectionModel;
-    }
-
-    public static EntityCollectionModel createStandalone(
-            ManagedObject collectionAsAdapter,
-            ModelAbstract<?> model) {
-
-        // dynamically determine the spec of the elements
-        // (ie so a List<Object> can be rendered according to the runtime type of its elements,
-        // rather than the compile-time type
-        val commonSuperClassFinder = new ClassExtensions.CommonSuperclassFinder();
-
-        val mementoService = model.getMementoService();
-
-        final List<ObjectMemento> mementoList = streamElementsOf(collectionAsAdapter) // pojos
-                .filter(_NullSafe::isPresent)
-                .peek(commonSuperClassFinder::collect)
-                .map(mementoService::mementoForPojo)
-                .collect(Collectors.toList());
-
-        val specificationLoader = model.getSpecificationLoader();
-
-        val elementSpec = commonSuperClassFinder.getCommonSuperclass()
-                .flatMap(specificationLoader::specForType)
-                .orElseGet(()->collectionAsAdapter.getSpecification().getElementSpecification().orElse(null));
-
-        final int pageSize = (elementSpec != null)
-                ? pageSize(elementSpec.getFacet(PagedFacet.class), PAGE_SIZE_DEFAULT_FOR_STANDALONE)
-                : PAGE_SIZE_DEFAULT_FOR_STANDALONE;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 
-        val elementType = (elementSpec != null)
-                ? elementSpec.getCorrespondingClass()
-                : Object.class;
-
-        val entityCollectionModel = new EntityCollectionModel(
-                model.getCommonContext(),
-                Variant.STANDALONE,
-                /*Identifier*/ null,
-                /*EntityModel*/null,
-                elementType,
-                pageSize);
-        entityCollectionModel.mementoList = mementoList;
-        return entityCollectionModel;
-
-    }
+public interface EntityCollectionModel
+extends
+    IModel<List<ManagedObject>>,
+    HasCommonContext,
+    LinksProvider {
 
     // -- VARIANTS
 
+    @RequiredArgsConstructor
     public enum Variant {
         /**
          * A simple list of object mementos, eg the result of invoking an action
@@ -158,426 +55,95 @@ implements
          * <p>
          * This deals with both persisted and transient objects.
          */
-        STANDALONE {
-            @Override
-            List<ManagedObject> load(EntityCollectionModel colModel) {
-
-                return loadElementsOneByOne(colModel).collect(Collectors.toList());
-            }
-
-
-            private Stream<ManagedObject> loadElementsOneByOne(final EntityCollectionModel model) {
-
-                return stream(model.mementoList)
-                        .map(model.getCommonContext()::reconstructObject)
-                        .filter(_NullSafe::isPresent);
-            }
-
-            @Override
-            void setObject(EntityCollectionModel colModel, List<ManagedObject> adapterList) {
-
-                //XXX lombok issue, cannot use val here
-                final ObjectMementoService mementoService = colModel.getMementoService();
-
-                colModel.mementoList = _NullSafe.stream(adapterList)
-                        .map(mementoService::mementoForObject)
-                        .filter(_NullSafe::isPresent)
-                        .collect(Collectors.toList());
-            }
-
-            @Override
-            public String getId(EntityCollectionModel colModel) {
-                return null;
-            }
-
-            @Override
-            public String getName(EntityCollectionModel colModel) {
-                PluralFacet facet = colModel.getTypeOfSpecification().getFacet(PluralFacet.class);
-                return facet.value();
-            }
-
-            @Override
-            public int getCount(EntityCollectionModel colModel) {
-                return colModel.mementoList.size();
-            }
-
-            @Override
-            public EntityModel.RenderingHint renderingHint() {
-                return EntityModel.RenderingHint.STANDALONE_PROPERTY_COLUMN;
-            }
-
-        },
+        STANDALONE(EntityModel.RenderingHint.STANDALONE_PROPERTY_COLUMN, 25),
 
         /**
          * A collection of an entity (eg Order/OrderDetail).
          */
-        PARENTED {
-            @Override
-            List<ManagedObject> load(EntityCollectionModel colModel) {
-
-                final ManagedObject adapter = colModel.getCommonContext()
-                        .reconstructObject(colModel.getParentObjectAdapterMemento());
-
-                final OneToManyAssociation collection = colModel.collectionMemento
-                        .getCollection(colModel.getSpecificationLoader());
-
-                final ManagedObject collectionAsAdapter = collection.get(adapter, InteractionInitiatedBy.USER);
-
-                final List<Object> objectList = asIterable(collectionAsAdapter);
+        PARENTED(EntityModel.RenderingHint.PARENTED_PROPERTY_COLUMN, 12),
+        ;
 
-                final Class<? extends Comparator<?>> sortedBy = colModel.sortedBy;
-                if(sortedBy != null) {
-                    @SuppressWarnings("unchecked")
-                    final Comparator<Object> comparator = (Comparator<Object>) _InstanceUtil.createInstance(sortedBy);
-                    colModel.getCommonContext().injectServicesInto(comparator);
-                    Collections.sort(objectList, comparator);
-                }
-
-                final List<ManagedObject> adapterList =
-                        _Lists.map(objectList, x-> colModel.getObjectManager().adapt(x));
-
-                return adapterList;
-            }
-
-            @SuppressWarnings("unchecked")
-            private List<Object> asIterable(ManagedObject collectionAsAdapter) {
-                if(collectionAsAdapter==null) {
-                    return Collections.emptyList();
-                }
-                final Iterable<Object> objects = (Iterable<Object>) collectionAsAdapter.getPojo();
-                return stream(objects).collect(Collectors.toList());
-            }
-
-            @Override
-            void setObject(EntityCollectionModel colModel, List<ManagedObject> list) {
-                // no-op
-                throw new UnsupportedOperationException();
-            }
-
-            @Override public String getId(EntityCollectionModel colModel) {
-                return colModel.getCollectionMemento().getCollectionId();
-            }
-
-            @Override
-            public String getName(EntityCollectionModel colModel) {
-                return colModel.getCollectionMemento().getCollectionName();
-            }
-
-            @Override
-            public int getCount(EntityCollectionModel colModel) {
-                return load(colModel).size();
-            }
-
-            @Override
-            public EntityModel.RenderingHint renderingHint() {
-                return EntityModel.RenderingHint.PARENTED_PROPERTY_COLUMN;
-            }
-
-        };
-
-        abstract List<ManagedObject> load(EntityCollectionModel entityCollectionModel);
-
-        abstract void setObject(EntityCollectionModel entityCollectionModel, List<ManagedObject> list);
-
-        public abstract String getId(EntityCollectionModel entityCollectionModel);
-        public abstract String getName(EntityCollectionModel entityCollectionModel);
-
-        public abstract int getCount(EntityCollectionModel entityCollectionModel);
-
-        public abstract EntityModel.RenderingHint renderingHint();
-    }
-
-
-    /**
-     * The {@link ActionModel model} of the {@link ObjectAction action}
-     * that generated this {@link EntityCollectionModel}.
-     *
-     * <p>
-     * Populated only for {@link Variant#STANDALONE standalone} collections.
-     *
-     * @see #setActionHint(ActionModel)
-     */
-    public ActionModel getActionModelHint() {
-        return actionModelHint;
-    }
-    /**
-     * Called only for {@link Variant#STANDALONE standalone} collections.
-     *
-     * @see #getActionModelHint()
-     */
-    public void setActionHint(ActionModel actionModelHint) {
-        this.actionModelHint = actionModelHint;
-    }
-
-    @Getter private final Variant variant;
-
-    private final Class<?> typeOf;
-    private transient Optional<ObjectSpecification> typeOfSpec;
-
-    /**
-     * Populated only if {@link Variant#STANDALONE}.
-     */
-    private List<ObjectMemento> mementoList;
-
-    /**
-     * Populated only if {@link Variant#STANDALONE}.
-     */
-    private Map<String, ObjectMemento> toggledMementos;
-
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     */
-    private final EntityModel entityModel;
-
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     * <p>
-     * This collection's <i>feature</i> {@link Identifier}.
-     * @see Identifier
-     */
-    @Getter private final Identifier identifier;
+        @Getter private final EntityModel.RenderingHint columnRenderingHint;
+        @Getter private final int pageSizeDefault;
 
 
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     */
-    private CollectionMemento collectionMemento;
-
-    @Getter private final int pageSize;
-
-    /**
-     * Additional links to render (if any)
-     */
-    private List<LinkAndLabel> linkAndLabels = _Lists.newArrayList();
-
-    /**
-     * Optionally populated only if {@link Variant#PARENTED}.
-     */
-    private Class<? extends Comparator<?>> sortedBy;
-
-    /**
-     * Optionally populated, only if {@link Variant#STANDALONE} (ie called from an action).
-     */
-    private ActionModel actionModelHint;
-
-    private EntityCollectionModel(
-            IsisAppCommonContext commonContext,
-            Variant type,
-            Identifier identifier,
-            EntityModel entityModel,
-            Class<?> typeOf,
-            int pageSize) {
-
-        super(commonContext);
-        this.variant = type;
-        this.identifier = identifier;
-        this.entityModel = entityModel;
-        this.typeOf = typeOf;
-        this.pageSize = pageSize;
-        this.toggledMementos = _Maps.<String, ObjectMemento>newLinkedHashMap();
-    }
-
-
-    private static OneToManyAssociation collectionFor(EntityModel entityModel) {
-
-        val collectionLayoutData = entityModel.getCollectionLayoutData();
-        if(collectionLayoutData == null) {
-            throw new IllegalArgumentException("EntityModel must have a CollectionLayoutMetadata");
+        public boolean isStandalone() {
+            return this == STANDALONE;
         }
 
-        val collectionId = collectionLayoutData.getId();
-        val spec = entityModel.getTypeOfSpecification();
-
-        return (OneToManyAssociation) spec.getAssociationElseFail(collectionId);
-    }
-
-    private static Class<?> forName(final ObjectSpecification objectSpec) {
-        final String fullName = objectSpec.getFullIdentifier();
-        return ClassUtil.forNameElseFail(fullName);
-    }
-
-
-    private static int pageSize(final PagedFacet pagedFacet, final int defaultPageSize) {
-        return pagedFacet != null ? pagedFacet.value(): defaultPageSize;
-    }
-
-    public boolean isParented() {
-        return variant == Variant.PARENTED;
-    }
-
-    public boolean isStandalone() {
-        return variant == Variant.STANDALONE;
-    }
-
-    /**
-     * The name of the collection (if has an entity, ie, if
-     * {@link #isParented() is parented}.)
-     *
-     * <p>
-     * If {@link #isStandalone()}, returns the {@link PluralFacet} of the {@link #getTypeOfSpecification() specification}
-     * (eg 'Customers').
-     */
-    public String getName() {
-        return variant.getName(this);
-    }
-
-    public int getCount() {
-        return this.variant.getCount(this);
-    }
-
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     */
-    public CollectionLayoutData getLayoutData() {
-        return entityModel != null
-                ? entityModel.getCollectionLayoutData()
-                : null;
-    }
-
-    @Override
-    protected List<ManagedObject> load() {
-        return variant.load(this);
-    }
-
-    public @Nullable ObjectSpecification getTypeOfSpecification() {
-        if (typeOfSpec == null) {
-            typeOfSpec = getSpecificationLoader().specForType(typeOf);
+        public boolean isParented() {
+            return this == PARENTED;
         }
-        return typeOfSpec.orElse(null);
-    }
-
-    @Override
-    public void setObject(List<ManagedObject> list) {
-        super.setObject(list);
-        variant.setObject(this, list);
     }
 
-    /**
-     * Not API, but to refresh the model list.
-     */
-    public void setObjectList(ManagedObject resultAdapter) {
-        this.mementoList = streamElementsOf(resultAdapter)
-                .map(super.getMementoService()::mementoForPojo)
-                .collect(Collectors.toList());
-    }
+    // -- FACTORIES
 
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     */
-    public EntityModel getEntityModel() {
-        return entityModel;
+    static EntityCollectionModelParented createParented(final @NonNull EntityModel entityModel) {
+        return EntityCollectionModelParented.forParentObjectModel(entityModel);
     }
 
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     */
-    public Optional<Bookmark> getParentObjectBookmark() {
-        return entityModel != null
-                ? entityModel.getManagedObject().getBookmark()
-                : Optional.empty();
+    static EntityCollectionModelStandalone createStandalone(
+            ManagedObject collectionAsAdapter,
+            ActionModel actionModel) {
+        return EntityCollectionModelStandalone.forActionModel(collectionAsAdapter, actionModel);
     }
 
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     */
-    public Optional<ObjectSpecification> getParentObjectSpecification() {
-        return getParentObjectBookmark()
-                .flatMap(bookmark->getCommonContext().getSpecificationLoader().specForBookmark(bookmark));
-    }
+    // -- IDENTITY
 
     /**
-     * Populated only if {@link Variant#PARENTED}.
+     * This collection's <i>feature</i> {@link Identifier}.
+     * @see Identifier
      */
-    @Deprecated // don't expose this implementation detail, use getParentObjectBookmark() instead
-    public ObjectMemento getParentObjectAdapterMemento() {
-        return entityModel != null? entityModel.memento(): null;
-    }
+    Identifier getIdentifier();
 
-    /**
-     * Populated only if {@link Variant#PARENTED}.
-     */
-    @Deprecated // don't expose this implementation detail
-    public CollectionMemento getCollectionMemento() {
-        return collectionMemento;
-    }
+    // -- VARIANT SUPPORT
 
-    private static Stream<?> streamElementsOf(ManagedObject resultAdapter) {
-        return _NullSafe.streamAutodetect(resultAdapter.getPojo());
-    }
+    Variant getVariant();
 
-    public boolean toggleSelectionOn(ManagedObject selectedAdapter) {
-        //XXX lombok issue, cannot use val here
-        final ObjectMemento selectedAsMemento = super.getMementoService().mementoForObject(selectedAdapter);
-        final String selectedKey = selectedAsMemento.asString();
+    default boolean isStandalone() { return getVariant().isStandalone(); }
+    default boolean isParented() { return getVariant().isParented(); }
 
-        final boolean isSelected = _Maps.toggleElement(toggledMementos, selectedKey, selectedAsMemento);
-        return isSelected;
+    // -- METAMODEL SUPPORT
 
-    }
+    ObjectSpecification getTypeOfSpecification();
+    ObjectMember getMetaModel();
 
-    public Can<ObjectMemento> getToggleMementosList() {
-        return Can.ofCollection(this.toggledMementos.values());
+    default Can<ObjectAction> getAssociatedActions() {
+        return Can.empty();
     }
 
-    public void clearToggleMementosList() {
-        this.toggledMementos.clear();
-    }
+    // -- INTERACTION SUPPORT
 
-    public void addLinkAndLabels(List<LinkAndLabel> linkAndLabels) {
-        this.linkAndLabels.clear();
-        this.linkAndLabels.addAll(linkAndLabels);
-    }
+    Optional<ManagedCollection> getManagedCollection();
 
-    @Override
-    public List<LinkAndLabel> getLinks() {
-        return Collections.unmodifiableList(linkAndLabels);
+    default Optional<ManagedObject> getParentObject() {
+        return getManagedCollection()
+                .map(ManagedCollection::getOwner);
     }
 
-    public EntityCollectionModel asDummy() {
-        final EntityCollectionModel dummy = new EntityCollectionModel(
-                super.getCommonContext(), Variant.STANDALONE, null, null, typeOf, pageSize);
-        dummy.mementoList = Collections.<ObjectMemento>emptyList();
-        return dummy;
+    default Optional<ObjectSpecification> getParentObjectSpecification() {
+        return getParentObject()
+                .map(ManagedObject::getSpecification);
     }
 
-    // //////////////////////////////////////
+    // -- TOGGLE SUPPORT
 
-    public static final String HINT_KEY_SELECTED_ITEM = "selectedItem";
+    Can<ObjectMemento> getToggleMementosList();
+    void clearToggleMementosList();
+    boolean toggleSelectionOn(ManagedObject selectedAdapter);
 
-    /**
-     * Just delegates to the {@link #getEntityModel() entity model} (if parented, else no-op).
-     */
-    @Override
-    public String getHint(final Component component, final String attributeName) {
-        if(getEntityModel() == null) {
-            return null;
-        }
-        return getEntityModel().getHint(component, attributeName);
-    }
+    // -- BASIC PROPERTIES
 
-    /**
-     * Just delegates to the {@link #getEntityModel() entity model} (if parented, else no-op).
-     */
-    @Override
-    public void setHint(final Component component, final String attributeName, final String attributeValue) {
-        if(getEntityModel() == null) {
-            return;
-        }
-        getEntityModel().setHint(component, attributeName, attributeValue);
-    }
-
-    /**
-     * Just delegates to the {@link #getEntityModel() entity model} (if parented, else no-op).
-     */
-    @Override
-    public void clearHint(final Component component, final String attributeName) {
-        if(getEntityModel() == null) {
-            return;
-        }
-        getEntityModel().clearHint(component, attributeName);
-    }
+    int getCount();
+    String getName();
+    int getPageSize();
 
+    // -- REFACTORING TODO ...
 
+    @Deprecated
+    ObjectMemento getParentObjectAdapterMemento();
 
+    @Deprecated
+    Bookmark asHintingBookmarkIfSupported();
 
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelAbstract.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelAbstract.java
new file mode 100644
index 0000000..909f3f6
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelAbstract.java
@@ -0,0 +1,105 @@
+package org.apache.isis.viewer.wicket.model.models;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.isis.applib.Identifier;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._NullSafe;
+import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.paged.PagedFacet;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.context.IsisAppCommonContext;
+import org.apache.isis.core.runtime.memento.ObjectMemento;
+import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
+
+import lombok.AccessLevel;
+import lombok.Getter;
+import lombok.NonNull;
+
+public abstract class EntityCollectionModelAbstract
+extends ModelAbstract<List<ManagedObject>>
+implements EntityCollectionModel {
+
+    private static final long serialVersionUID = 1L;
+
+    @Getter(onMethod_ = {@Override}) private final @NonNull Identifier identifier;
+    @Getter private final int pageSize;
+
+    protected EntityCollectionModelAbstract(
+            final @NonNull IsisAppCommonContext commonContext,
+            final @NonNull Identifier identifier,
+            final @NonNull ObjectSpecification typeOfSpecification,
+            final @NonNull Can<FacetHolder> facetHolders) {
+        super(commonContext);
+        this.identifier = identifier;
+        this.typeOfSpecification = Optional.of(typeOfSpecification); // as an optimization: memoize transient
+        this.elementType = typeOfSpecification.getCorrespondingClass();
+        this.pageSize = facetHolders.stream()
+        .map(facetHolder->facetHolder.getFacet(PagedFacet.class))
+        .filter(_NullSafe::isPresent)
+        .findFirst()
+        .map(PagedFacet::value)
+        .orElse(getVariant().getPageSizeDefault());
+
+        this.toggledMementos = _Maps.<String, ObjectMemento>newLinkedHashMap();
+    }
+
+    // -- TYPE OF (ELEMENT TYPE)
+
+    @Getter(value = AccessLevel.PROTECTED) private final @NonNull Class<?> elementType;
+
+    private transient Optional<ObjectSpecification> typeOfSpecification;
+
+    @Override
+    public ObjectSpecification getTypeOfSpecification() {
+        if(typeOfSpecification==null) {
+            typeOfSpecification = getSpecificationLoader().specForType(elementType);
+        }
+        return typeOfSpecification.orElse(null);
+    }
+
+    // -- LINKS PROVIDER
+
+    /**
+     * Additional links to render (if any)
+     */
+    private List<LinkAndLabel> linkAndLabels = _Lists.newArrayList();
+
+    public void setLinkAndLabels(final @NonNull Iterable<LinkAndLabel> linkAndLabels) {
+        this.linkAndLabels.clear();
+        linkAndLabels.forEach(this.linkAndLabels::add);
+    }
+
+    @Override
+    public final Can<LinkAndLabel> getLinks() {
+        return Can.ofCollection(linkAndLabels);
+    }
+
+    // -- TOGGLE SUPPORT
+
+    @Getter private LinkedHashMap<String, ObjectMemento> toggledMementos;
+
+    @Override
+    public Can<ObjectMemento> getToggleMementosList() {
+        return Can.ofCollection(this.toggledMementos.values());
+    }
+
+    @Override
+    public void clearToggleMementosList() {
+        this.toggledMementos.clear();
+    }
+
+    @Override
+    public boolean toggleSelectionOn(final ManagedObject selectedAdapter) {
+        final ObjectMemento selectedAsMemento = super.getMementoService().mementoForObject(selectedAdapter);
+        final String selectedKey = selectedAsMemento.asString();
+        final boolean isSelected = _Maps.toggleElement(toggledMementos, selectedKey, selectedAsMemento);
+        return isSelected;
+    }
+
+}
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelDummy.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelDummy.java
new file mode 100644
index 0000000..305dd89
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelDummy.java
@@ -0,0 +1,93 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.wicket.model.models;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.runtime.memento.ObjectMemento;
+
+import lombok.NonNull;
+
+public class EntityCollectionModelDummy
+extends EntityCollectionModelAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    public static EntityCollectionModelDummy forCollectionModel(
+            final @NonNull EntityCollectionModel collectionModel) {
+        return new EntityCollectionModelDummy(collectionModel);
+    }
+
+    protected EntityCollectionModelDummy(
+            final @NonNull EntityCollectionModel collectionModel) {
+        super(collectionModel.getCommonContext(),
+                collectionModel.getIdentifier(),
+                collectionModel.getTypeOfSpecification(),
+                Can.empty());
+    }
+
+    @Override
+    public Variant getVariant() {
+        return Variant.STANDALONE;
+    }
+
+    @Override
+    public Optional<ManagedCollection> getManagedCollection() {
+        return Optional.empty();
+    }
+
+    @Override
+    public int getCount() {
+        return 0;
+    }
+
+    @Override
+    public String getName() {
+        return "dummy";
+    }
+
+    @Override
+    protected List<ManagedObject> load() {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public OneToManyAssociation getMetaModel() {
+        throw _Exceptions.unsupportedOperation();
+    }
+
+    @Override
+    public ObjectMemento getParentObjectAdapterMemento() {
+        throw _Exceptions.unsupportedOperation();
+    }
+
+    @Override
+    public Bookmark asHintingBookmarkIfSupported() {
+        return null;
+    }
+
+}
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelParented.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelParented.java
new file mode 100644
index 0000000..eae2837
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelParented.java
@@ -0,0 +1,191 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.wicket.model.models;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.wicket.Component;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.applib.layout.component.CollectionLayoutData;
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.assertions._Assert;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.actcoll.typeof.TypeOfFacet;
+import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+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;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.runtime.memento.ObjectMemento;
+import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
+
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.val;
+
+public class EntityCollectionModelParented
+extends EntityCollectionModelAbstract
+implements
+    UiHintContainer {
+
+    private static final long serialVersionUID = 1L;
+
+    private final @NonNull _EntityCollectionModelLegacy legacy;
+
+    // TODO parent object model, should be private
+    @Getter private final @NonNull EntityModel entityModel;
+
+    // -- FACTORIES
+
+    public static EntityCollectionModelParented forParentObjectModel(
+            final @NonNull EntityModel entityModel) {
+
+        val collectionMetaModel =
+                Optional.ofNullable(entityModel.getCollectionLayoutData())
+                .map(collectionLayoutData->
+                    entityModel
+                        .getTypeOfSpecification()
+                        .getCollectionElseFail(collectionLayoutData.getId()))
+                .orElseThrow(()->_Exceptions
+                        .illegalArgument("EntityModel must have CollectionLayoutMetadata"));
+
+        val typeOfFacet = collectionMetaModel.lookupFacet(TypeOfFacet.class)
+                .orElseThrow(()->_Exceptions
+                        .illegalArgument("CollectionMetaModel must have a TypeOfFacet"));
+
+        val typeOfSpecification = typeOfFacet.valueSpec();
+
+        final Can<FacetHolder> facetHolders = Can.of(collectionMetaModel, typeOfSpecification);
+
+//      val sortedByFacet = collectionMetaModel.getFacet(SortedByFacet.class);
+//
+//        entityCollectionModel.collectionMemento = new CollectionMemento(collectionMetaModel);
+//        entityCollectionModel.sortedBy = (sortedByFacet != null)
+//                ? sortedByFacet.value()
+//                : null;
+
+        return new EntityCollectionModelParented(
+                collectionMetaModel, typeOfSpecification, entityModel, facetHolders);
+    }
+
+    // -- CONSTRUCTOR
+
+    protected EntityCollectionModelParented(
+            final @NonNull OneToManyAssociation collectionMetaModel,
+            final @NonNull ObjectSpecification typeOfSpecification,
+            final @NonNull EntityModel parentObjectModel,
+            final @NonNull Can<FacetHolder> facetHolders) {
+        super(
+                parentObjectModel.getCommonContext(),
+                collectionMetaModel.getIdentifier(),
+                typeOfSpecification,
+                facetHolders);
+        this.entityModel = parentObjectModel;
+        this.legacy = _EntityCollectionModelLegacy.createParented(entityModel);
+    }
+
+    // -- VARIANT SUPPORT
+
+    @Override
+    public Variant getVariant() {
+        return Variant.PARENTED;
+    }
+
+    // -- METAMODEL
+
+    @Override
+    public Can<ObjectAction> getAssociatedActions() {
+        val managedCollection = getManagedCollection().orElse(null);
+        if(managedCollection==null) {
+            return Can.empty();
+        }
+        final OneToManyAssociation collection = managedCollection.getCollection();
+        return managedCollection.getOwner().getSpecification()
+                .streamRuntimeActions(MixedIn.INCLUDED)
+                .filter(ObjectAction.Predicates.associatedWithAndWithCollectionParameterFor(collection))
+                .collect(Can.toCan());
+    }
+
+    // -- UI HINT CONTAINER
+
+    public static final String HINT_KEY_SELECTED_ITEM = "selectedItem";
+
+    @Override
+    public String getHint(final Component component, final String attributeName) {
+        return getEntityModel().getHint(component, attributeName);
+    }
+
+    @Override
+    public void setHint(final Component component, final String attributeName, final String attributeValue) {
+        getEntityModel().setHint(component, attributeName, attributeValue);
+    }
+
+    @Override
+    public void clearHint(final Component component, final String attributeName) {
+        getEntityModel().clearHint(component, attributeName);
+    }
+
+    @Override
+    protected List<ManagedObject> load() {
+        return legacy.load();
+    }
+
+    @Override
+    public Optional<ManagedCollection> getManagedCollection() {
+        return Optional.of(ManagedCollection
+                .of(entityModel.getManagedObject(), getMetaModel(), Where.NOT_SPECIFIED));
+    }
+
+    @Override
+    public int getCount() {
+        return legacy.getCount();
+    }
+
+    @Override
+    public String getName() {
+        _Assert.assertEquals(getMetaModel().getName(), legacy.getName());
+        return getMetaModel().getName();
+    }
+
+    @Override
+    public OneToManyAssociation getMetaModel() {
+        return legacy.getCollectionMemento().getCollection(getSpecificationLoader());
+    }
+
+    public CollectionLayoutData getLayoutData() {
+        return entityModel.getCollectionLayoutData();
+    }
+
+    @Override
+    public ObjectMemento getParentObjectAdapterMemento() {
+        return entityModel.memento();
+    }
+
+    @Override
+    public Bookmark asHintingBookmarkIfSupported() {
+        return entityModel.asHintingBookmarkIfSupported();
+    }
+
+
+}
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelStandalone.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelStandalone.java
new file mode 100644
index 0000000..2ee8cc7
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModelStandalone.java
@@ -0,0 +1,133 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.wicket.model.models;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.plural.PluralFacet;
+import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.runtime.memento.ObjectMemento;
+
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.val;
+
+public class EntityCollectionModelStandalone
+extends EntityCollectionModelAbstract {
+
+    private static final long serialVersionUID = 1L;
+
+    private final @NonNull _EntityCollectionModelLegacy legacy;
+
+    // parent object model
+    @Getter
+    private final @NonNull ActionModel actionModel;
+
+    // -- FACTORIES
+
+    public static EntityCollectionModelStandalone forActionModel(
+            final @NonNull ManagedObject collectionAsAdapter,
+            final @NonNull ActionModel actionModel) {
+
+        val typeOfSpecification = actionModel.getMetaModel().getReturnType().getElementSpecification()
+                .orElseThrow(()->_Exceptions
+                        .illegalArgument("ActionModel must have an ElementSpecification for its return type"));
+
+        final Can<FacetHolder> facetHolders = Can.of(actionModel.getMetaModel(), typeOfSpecification);
+
+        // take a copy of the actionModel,
+        // because the original can get mutated (specifically: its arguments cleared)
+        return new EntityCollectionModelStandalone(
+                typeOfSpecification, collectionAsAdapter, actionModel.copy(), facetHolders);
+    }
+
+    // -- CONSTRUCTOR
+
+    protected EntityCollectionModelStandalone(
+            final @NonNull ObjectSpecification typeOfSpecification,
+            final @NonNull ManagedObject collectionAsAdapter,
+            final @NonNull ActionModel actionModel,
+            final @NonNull Can<FacetHolder> facetHolders) {
+        super(
+                actionModel.getCommonContext(),
+                actionModel.getMetaModel().getIdentifier(),
+                typeOfSpecification,
+                facetHolders);
+        this.actionModel = actionModel;
+        this.legacy = _EntityCollectionModelLegacy.createStandalone(collectionAsAdapter, actionModel);
+    }
+
+    // -- VARIANT SUPPORT
+
+    @Override
+    public Variant getVariant() {
+        return Variant.STANDALONE;
+    }
+
+    // -- INTERACTION SUPPORT
+
+    @Override
+    public Optional<ManagedCollection> getManagedCollection() {
+        return Optional.empty();
+    }
+
+    // --
+
+    @Override
+    protected List<ManagedObject> load() {
+        return legacy.load();
+    }
+
+    @Override
+    public int getCount() {
+        return legacy.getCount();
+    }
+
+    @Override
+    public String getName() {
+        return getTypeOfSpecification().lookupFacet(PluralFacet.class)
+                .map(PluralFacet::value)
+                .orElse(getMetaModel().getName());
+    }
+
+    @Override
+    public ObjectMember getMetaModel() {
+        return actionModel.getMetaModel();
+    }
+
+    @Override
+    public ObjectMemento getParentObjectAdapterMemento() {
+        return legacy.getParentObjectAdapterMemento();
+    }
+
+    @Override
+    public Bookmark asHintingBookmarkIfSupported() {
+        return null;
+    }
+
+
+}
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 9a881e6..6c21b99 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
@@ -18,7 +18,6 @@
  */
 package org.apache.isis.viewer.wicket.model.models;
 
-import java.util.Collections;
 import java.util.List;
 import java.util.Optional;
 
@@ -59,8 +58,8 @@ import lombok.Setter;
  *
  */
 //@Log4j2
-public abstract class ScalarModel 
-extends ManagedObjectModel 
+public abstract class ScalarModel
+extends ManagedObjectModel
 implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext {
 
     private static final long serialVersionUID = 1L;
@@ -72,18 +71,18 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
     @NonNull private final Kind kind;
     public boolean isProperty() { return kind == Kind.PROPERTY; }
     public boolean isParameter() { return kind == Kind.PARAMETER; }
-    
+
 
     private final EntityModel parentEntityModel;
-    
-    @Getter(onMethod = @__(@Override)) 
-    @Setter(onMethod = @__(@Override)) 
+
+    @Getter(onMethod = @__(@Override))
+    @Setter(onMethod = @__(@Override))
     private Mode mode;
-    
-    @Getter(onMethod = @__(@Override)) 
-    @Setter(onMethod = @__(@Override)) 
+
+    @Getter(onMethod = @__(@Override))
+    @Setter(onMethod = @__(@Override))
     private RenderingHint renderingHint;
-    
+
 
     /**
      * Creates a model representing an action parameter of an action of a parent
@@ -91,9 +90,9 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
      * value (if any) of that action parameter.
      */
     protected ScalarModel(EntityModel parentEntityModel, ActionParameterMemento apm) {
-        
+
         super(parentEntityModel.getCommonContext());
-        
+
         this.kind = Kind.PARAMETER;
         this.parentEntityModel = parentEntityModel;
         this.pendingModel = new PendingModel(this);
@@ -107,11 +106,11 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
      * property.
      */
     protected ScalarModel(
-            EntityModel parentEntityModel, 
+            EntityModel parentEntityModel,
             PropertyMemento pm,
-            ObjectUiModel.Mode mode, 
+            ObjectUiModel.Mode mode,
             ObjectUiModel.RenderingHint renderingHint) {
-        
+
         super(parentEntityModel.getCommonContext());
         this.kind = Kind.PROPERTY;
         this.parentEntityModel = parentEntityModel;
@@ -134,12 +133,12 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
     @Override
     public ManagedObject getOwner() {
 //        if(owner==null) {
-//            owner = getParentUiModel().load(); 
+//            owner = getParentUiModel().load();
 //        }
 //        return owner;
         return getParentUiModel().load();
     }
-    
+
     /**
      * Whether the scalar represents a {@link Kind#PROPERTY property} or a
      * {@link Kind#PARAMETER}.
@@ -151,7 +150,7 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
     /**
      * Overrides superclass' implementation, because a {@link ScalarModel} can
      * know the {@link ObjectSpecification of} the {@link ManagedObject adapter}
-     * without there necessarily having any adapter 
+     * without there necessarily having any adapter
      * {@link #setObject(ManagedObject) set}.
      */
     @Override
@@ -164,7 +163,7 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
         return Optional.ofNullable(getScalarTypeSpec())
                 .map(ObjectSpecification::getLogicalType);
     }
-    
+
 
     public boolean isScalarTypeAnyOf(final Class<?>... requiredClass) {
         final String fullName = getTypeOfSpecification().getFullIdentifier();
@@ -221,8 +220,8 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
     private List<LinkAndLabel> linkAndLabels = _Lists.newArrayList();
 
     @Override
-    public List<LinkAndLabel> getLinks() {
-        return Collections.unmodifiableList(linkAndLabels);
+    public Can<LinkAndLabel> getLinks() {
+        return Can.ofCollection(linkAndLabels);
     }
 
     @Override
@@ -322,7 +321,7 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
      * @return <tt>true</tt> if the widget for this model must be editable.
      */
     public boolean mustBeEditable() {
-        return getMode() == Mode.EDIT 
+        return getMode() == Mode.EDIT
                 || getKind() == Kind.PARAMETER
                 || hasAssociatedActionWithInlineAsIfEdit();
     }
@@ -334,7 +333,7 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
      */
     @Override
     public boolean isInlinePrompt() {
-        return (getPromptStyle().isInline() && canEnterEditMode()) 
+        return (getPromptStyle().isInline() && canEnterEditMode())
                 || hasAssociatedActionWithInlineAsIfEdit();
     }
 
@@ -355,15 +354,15 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
         }
         return associatedActions;
     }
-    
+
     protected abstract Can<ObjectAction> calcAssociatedActions();
-    
+
     public final boolean hasAssociatedActionWithInlineAsIfEdit() {
         return getAssociatedActions().hasAssociatedActionWithInlineAsIfEdit();
     }
-    
+
     // -- PENDING STUFF
-    
+
     @Getter(value = AccessLevel.PACKAGE)
     private final PendingModel pendingModel;
 
@@ -375,7 +374,7 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
         pendingModel.clearPending();
     }
 
-    
+
     // --
-    
+
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/_EntityCollectionModelLegacy.java
similarity index 88%
copy from viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
copy to viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/_EntityCollectionModelLegacy.java
index 66ea614..0bf2c71 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/_EntityCollectionModelLegacy.java
@@ -72,7 +72,8 @@ import lombok.val;
  * So that the model is {@link Serializable}, the {@link ManagedObject}s within
  * the collection are stored as {@link ObjectMemento}s.
  */
-public class EntityCollectionModel
+@Deprecated
+class _EntityCollectionModelLegacy
 extends ModelAbstract<List<ManagedObject>>
 implements
     LinksProvider,
@@ -85,14 +86,15 @@ implements
 
     // -- FACTORIES
 
-    public static EntityCollectionModel createParented(EntityModel entityModel) {
+    public static _EntityCollectionModelLegacy createParented(EntityModel entityModel) {
 
         val oneToManyAssociation = collectionFor(entityModel);
         val typeOf = forName(oneToManyAssociation.getSpecification());
-        final int pageSize = pageSize(oneToManyAssociation.getFacet(PagedFacet.class), PAGE_SIZE_DEFAULT_FOR_PARENTED);
+        final int pageSize = PagedFacet.pageSizeOrDefault(
+                oneToManyAssociation.getFacet(PagedFacet.class), PAGE_SIZE_DEFAULT_FOR_PARENTED);
         val sortedByFacet = oneToManyAssociation.getFacet(SortedByFacet.class);
 
-        val entityCollectionModel = new EntityCollectionModel(
+        val entityCollectionModel = new _EntityCollectionModelLegacy(
                 entityModel.getCommonContext(),
                 Variant.PARENTED,
                 oneToManyAssociation.getIdentifier(),
@@ -106,7 +108,7 @@ implements
         return entityCollectionModel;
     }
 
-    public static EntityCollectionModel createStandalone(
+    public static _EntityCollectionModelLegacy createStandalone(
             ManagedObject collectionAsAdapter,
             ModelAbstract<?> model) {
 
@@ -130,14 +132,14 @@ implements
                 .orElseGet(()->collectionAsAdapter.getSpecification().getElementSpecification().orElse(null));
 
         final int pageSize = (elementSpec != null)
-                ? pageSize(elementSpec.getFacet(PagedFacet.class), PAGE_SIZE_DEFAULT_FOR_STANDALONE)
+                ? PagedFacet.pageSizeOrDefault(elementSpec.getFacet(PagedFacet.class), PAGE_SIZE_DEFAULT_FOR_STANDALONE)
                 : PAGE_SIZE_DEFAULT_FOR_STANDALONE;
 
         val elementType = (elementSpec != null)
                 ? elementSpec.getCorrespondingClass()
                 : Object.class;
 
-        val entityCollectionModel = new EntityCollectionModel(
+        val entityCollectionModel = new _EntityCollectionModelLegacy(
                 model.getCommonContext(),
                 Variant.STANDALONE,
                 /*Identifier*/ null,
@@ -160,13 +162,13 @@ implements
          */
         STANDALONE {
             @Override
-            List<ManagedObject> load(EntityCollectionModel colModel) {
+            List<ManagedObject> load(_EntityCollectionModelLegacy colModel) {
 
                 return loadElementsOneByOne(colModel).collect(Collectors.toList());
             }
 
 
-            private Stream<ManagedObject> loadElementsOneByOne(final EntityCollectionModel model) {
+            private Stream<ManagedObject> loadElementsOneByOne(final _EntityCollectionModelLegacy model) {
 
                 return stream(model.mementoList)
                         .map(model.getCommonContext()::reconstructObject)
@@ -174,7 +176,7 @@ implements
             }
 
             @Override
-            void setObject(EntityCollectionModel colModel, List<ManagedObject> adapterList) {
+            void setObject(_EntityCollectionModelLegacy colModel, List<ManagedObject> adapterList) {
 
                 //XXX lombok issue, cannot use val here
                 final ObjectMementoService mementoService = colModel.getMementoService();
@@ -186,18 +188,18 @@ implements
             }
 
             @Override
-            public String getId(EntityCollectionModel colModel) {
+            public String getId(_EntityCollectionModelLegacy colModel) {
                 return null;
             }
 
             @Override
-            public String getName(EntityCollectionModel colModel) {
+            protected String getName(_EntityCollectionModelLegacy colModel) {
                 PluralFacet facet = colModel.getTypeOfSpecification().getFacet(PluralFacet.class);
                 return facet.value();
             }
 
             @Override
-            public int getCount(EntityCollectionModel colModel) {
+            public int getCount(_EntityCollectionModelLegacy colModel) {
                 return colModel.mementoList.size();
             }
 
@@ -213,7 +215,7 @@ implements
          */
         PARENTED {
             @Override
-            List<ManagedObject> load(EntityCollectionModel colModel) {
+            List<ManagedObject> load(_EntityCollectionModelLegacy colModel) {
 
                 final ManagedObject adapter = colModel.getCommonContext()
                         .reconstructObject(colModel.getParentObjectAdapterMemento());
@@ -249,22 +251,22 @@ implements
             }
 
             @Override
-            void setObject(EntityCollectionModel colModel, List<ManagedObject> list) {
+            void setObject(_EntityCollectionModelLegacy colModel, List<ManagedObject> list) {
                 // no-op
                 throw new UnsupportedOperationException();
             }
 
-            @Override public String getId(EntityCollectionModel colModel) {
+            @Override public String getId(_EntityCollectionModelLegacy colModel) {
                 return colModel.getCollectionMemento().getCollectionId();
             }
 
             @Override
-            public String getName(EntityCollectionModel colModel) {
+            protected String getName(_EntityCollectionModelLegacy colModel) {
                 return colModel.getCollectionMemento().getCollectionName();
             }
 
             @Override
-            public int getCount(EntityCollectionModel colModel) {
+            public int getCount(_EntityCollectionModelLegacy colModel) {
                 return load(colModel).size();
             }
 
@@ -275,14 +277,14 @@ implements
 
         };
 
-        abstract List<ManagedObject> load(EntityCollectionModel entityCollectionModel);
+        abstract List<ManagedObject> load(_EntityCollectionModelLegacy entityCollectionModel);
 
-        abstract void setObject(EntityCollectionModel entityCollectionModel, List<ManagedObject> list);
+        abstract void setObject(_EntityCollectionModelLegacy entityCollectionModel, List<ManagedObject> list);
 
-        public abstract String getId(EntityCollectionModel entityCollectionModel);
-        public abstract String getName(EntityCollectionModel entityCollectionModel);
+        public abstract String getId(_EntityCollectionModelLegacy entityCollectionModel);
+        protected abstract String getName(_EntityCollectionModelLegacy entityCollectionModel);
 
-        public abstract int getCount(EntityCollectionModel entityCollectionModel);
+        public abstract int getCount(_EntityCollectionModelLegacy entityCollectionModel);
 
         public abstract EntityModel.RenderingHint renderingHint();
     }
@@ -290,7 +292,7 @@ implements
 
     /**
      * The {@link ActionModel model} of the {@link ObjectAction action}
-     * that generated this {@link EntityCollectionModel}.
+     * that generated this {@link _EntityCollectionModelLegacy}.
      *
      * <p>
      * Populated only for {@link Variant#STANDALONE standalone} collections.
@@ -360,7 +362,7 @@ implements
      */
     private ActionModel actionModelHint;
 
-    private EntityCollectionModel(
+    private _EntityCollectionModelLegacy(
             IsisAppCommonContext commonContext,
             Variant type,
             Identifier identifier,
@@ -397,10 +399,6 @@ implements
     }
 
 
-    private static int pageSize(final PagedFacet pagedFacet, final int defaultPageSize) {
-        return pagedFacet != null ? pagedFacet.value(): defaultPageSize;
-    }
-
     public boolean isParented() {
         return variant == Variant.PARENTED;
     }
@@ -529,12 +527,12 @@ implements
     }
 
     @Override
-    public List<LinkAndLabel> getLinks() {
-        return Collections.unmodifiableList(linkAndLabels);
+    public Can<LinkAndLabel> getLinks() {
+        return Can.ofCollection(linkAndLabels);
     }
 
-    public EntityCollectionModel asDummy() {
-        final EntityCollectionModel dummy = new EntityCollectionModel(
+    public _EntityCollectionModelLegacy asDummy() {
+        final _EntityCollectionModelLegacy dummy = new _EntityCollectionModelLegacy(
                 super.getCommonContext(), Variant.STANDALONE, null, null, typeOf, pageSize);
         dummy.mementoList = Collections.<ObjectMemento>emptyList();
         return dummy;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
index a441988..edb1835 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
@@ -49,15 +49,15 @@ import lombok.val;
 public enum ActionResultResponseType {
     OBJECT {
         @Override
-        public ActionResultResponse interpretResult(ActionModel model, AjaxRequestTarget target, ManagedObject resultAdapter) {
-            val commonContext = model.getCommonContext();
+        public ActionResultResponse interpretResult(ActionModel actionModel, AjaxRequestTarget target, ManagedObject resultAdapter) {
+            val commonContext = actionModel.getCommonContext();
             val actualAdapter = determineActualAdapter(commonContext, resultAdapter); // intercepts collections
-            return toEntityPage(model, actualAdapter);
+            return toEntityPage(actionModel, actualAdapter);
         }
 
         @Override
-        public ActionResultResponse interpretResult(ActionModel model, ManagedObject targetAdapter) {
-            final ActionResultResponse actionResultResponse = toEntityPage(model, targetAdapter);
+        public ActionResultResponse interpretResult(ActionModel actionModel, ManagedObject targetAdapter) {
+            final ActionResultResponse actionResultResponse = toEntityPage(actionModel, targetAdapter);
             return actionResultResponse;
         }
     },
@@ -65,9 +65,6 @@ public enum ActionResultResponseType {
         @Override
         public ActionResultResponse interpretResult(ActionModel actionModel, AjaxRequestTarget target, ManagedObject resultAdapter) {
             val collectionModel = EntityCollectionModel.createStandalone(resultAdapter, actionModel);
-            // take a copy of the actionModel, because the original can get mutated (specifically: its arguments cleared)
-            val actionModelCopy = actionModel.copy();
-            collectionModel.setActionHint(actionModelCopy);
             return ActionResultResponse.toPage(new StandaloneCollectionPage(collectionModel));
         }
     },
@@ -151,7 +148,7 @@ public enum ActionResultResponseType {
     }
 
     private static ManagedObject determineActualAdapter(
-            IsisAppCommonContext commonContext, 
+            IsisAppCommonContext commonContext,
             ManagedObject resultAdapter) {
 
         if (resultAdapter.getSpecification().isNotCollection()) {
@@ -169,7 +166,7 @@ public enum ActionResultResponseType {
     }
 
     private static ActionResultResponse toEntityPage(
-            final ActionModel model, 
+            final ActionModel model,
             final ManagedObject actualAdapter) {
 
         // this will not preserve the URL (because pageParameters are not copied over)
@@ -186,7 +183,7 @@ public enum ActionResultResponseType {
             final ActionModel model,
             final AjaxRequestTarget targetIfAny,
             final ManagedObject resultAdapter) {
-        
+
         ActionResultResponseType arrt = determineFor(resultAdapter, targetIfAny);
         return arrt.interpretResult(model, targetIfAny, resultAdapter);
     }
@@ -194,11 +191,11 @@ public enum ActionResultResponseType {
     private static ActionResultResponseType determineFor(
             final ManagedObject resultAdapter,
             AjaxRequestTarget targetIfAny) {
-        
+
         if(resultAdapter == null) {
             return ActionResultResponseType.VOID;
         }
-        
+
         final ObjectSpecification resultSpec = resultAdapter.getSpecification();
         if (resultSpec.isNotCollection()) {
             if (resultSpec.getFacet(ValueFacet.class) != null) {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
index ee7d79e..5652db7 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsDropDownPanel.java
@@ -19,15 +19,14 @@
 
 package org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions;
 
-import java.util.List;
-
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 
 public class AdditionalLinksAsDropDownPanel extends AdditionalLinksPanel {
 
     private static final long serialVersionUID = 1L;
 
-    public AdditionalLinksAsDropDownPanel(String id, List<LinkAndLabel> links) {
+    public AdditionalLinksAsDropDownPanel(String id, Can<LinkAndLabel> links) {
         super(id, links);
     }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java
index c627ebb..9f5e4fd 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksAsListInlinePanel.java
@@ -19,15 +19,14 @@
 
 package org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions;
 
-import java.util.List;
-
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 
 public class AdditionalLinksAsListInlinePanel extends AdditionalLinksPanel {
 
     private static final long serialVersionUID = 1L;
 
-    public AdditionalLinksAsListInlinePanel(String id, List<LinkAndLabel> links) {
+    public AdditionalLinksAsListInlinePanel(String id, Can<LinkAndLabel> links) {
         super(id, links);
     }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksPanel.java
index 76e1a6f..cc19b50 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/AdditionalLinksPanel.java
@@ -28,6 +28,7 @@ import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.model.Model;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.viewer.common.model.decorator.confirm.ConfirmUiModel;
 import org.apache.isis.viewer.common.model.decorator.confirm.ConfirmUiModel.Placement;
@@ -42,7 +43,7 @@ import org.apache.isis.viewer.wicket.ui.util.Tooltips;
 
 import lombok.val;
 
-public class AdditionalLinksPanel 
+public class AdditionalLinksPanel
 extends PanelAbstract<List<LinkAndLabel>, ListOfLinksModel> {
 
     private static final long serialVersionUID = 1L;
@@ -56,23 +57,23 @@ extends PanelAbstract<List<LinkAndLabel>, ListOfLinksModel> {
     public enum Style {
         INLINE_LIST {
             @Override
-            AdditionalLinksPanel newPanel(String id, List<LinkAndLabel> links) {
+            AdditionalLinksPanel newPanel(String id, Can<LinkAndLabel> links) {
                 return new AdditionalLinksAsListInlinePanel(id, links);
             }
         },
         DROPDOWN {
             @Override
-            AdditionalLinksPanel newPanel(String id, List<LinkAndLabel> links) {
+            AdditionalLinksPanel newPanel(String id, Can<LinkAndLabel> links) {
                 return new AdditionalLinksAsDropDownPanel(id, links);
             }
         };
-        abstract AdditionalLinksPanel newPanel(String id, List<LinkAndLabel> links);
+        abstract AdditionalLinksPanel newPanel(String id, Can<LinkAndLabel> links);
     }
 
     public static AdditionalLinksPanel addAdditionalLinks(
             final MarkupContainer markupContainer,
             final String id,
-            final List<LinkAndLabel> links,
+            final Can<LinkAndLabel> links,
             final Style style) {
         if(links.isEmpty()) {
             Components.permanentlyHide(markupContainer, id);
@@ -85,9 +86,9 @@ extends PanelAbstract<List<LinkAndLabel>, ListOfLinksModel> {
     }
 
     protected AdditionalLinksPanel(
-            String id, 
-            List<LinkAndLabel> linksDoNotUseDirectlyInsteadUseOfListOfLinksModel) {
-        
+            String id,
+            Can<LinkAndLabel> linksDoNotUseDirectlyInsteadUseOfListOfLinksModel) {
+
         super(id, new ListOfLinksModel(linksDoNotUseDirectlyInsteadUseOfListOfLinksModel));
 
 
@@ -104,8 +105,8 @@ extends PanelAbstract<List<LinkAndLabel>, ListOfLinksModel> {
         container.setOutputMarkupId(true);
 
         setOutputMarkupId(true);
-        
-        final ListView<LinkAndLabel> listView = 
+
+        final ListView<LinkAndLabel> listView =
                 new ListView<LinkAndLabel>(ID_ADDITIONAL_LINK_ITEM, getModel()) {
 
             private static final long serialVersionUID = 1L;
@@ -124,9 +125,9 @@ extends PanelAbstract<List<LinkAndLabel>, ListOfLinksModel> {
                         final String reasonDisabledIfAny = actionLink.getReasonDisabledIfAny();
                         return first(reasonDisabledIfAny, actionMeta.getDescription());
                     }
-                } 
+                }
                 : Model.of(actionMeta.getDescription());
-                
+
                 Tooltips.addTooltip(link, tooltipModel.getObject());
 
                 val viewTitleLabel = new Label(ID_ADDITIONAL_LINK_TITLE, actionMeta.getLabel());
@@ -138,10 +139,10 @@ extends PanelAbstract<List<LinkAndLabel>, ListOfLinksModel> {
                 }
                 link.add(new CssClassAppender(actionMeta.getActionIdentifier()));
 
-                if (actionMeta.getSemantics().isAreYouSure()) { 
+                if (actionMeta.getSemantics().isAreYouSure()) {
                     if(actionMeta.getParameters().isNoParameters()) {
-                        val hasDisabledReason = link instanceof ActionLink 
-                                ? _Strings.isNotEmpty(((ActionLink)link).getReasonDisabledIfAny()) 
+                        val hasDisabledReason = link instanceof ActionLink
+                                ? _Strings.isNotEmpty(((ActionLink)link).getReasonDisabledIfAny())
                                 : false;
                         if (!hasDisabledReason) {
                             val confirmUiModel = ConfirmUiModel.ofAreYouSure(getTranslationService(), Placement.BOTTOM);
@@ -164,7 +165,7 @@ extends PanelAbstract<List<LinkAndLabel>, ListOfLinksModel> {
 
                 item.addOrReplace(link);
             }
-            
+
         };
 
         container.addOrReplace(listView);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java
index f7c1522..1502630 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java
@@ -18,11 +18,8 @@
  */
 package org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions;
 
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
-import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
@@ -35,23 +32,23 @@ import lombok.experimental.UtilityClass;
 @UtilityClass
 public final class LinkAndLabelUtil {
 
-    public static List<LinkAndLabel> asActionLinks(
+    public static Stream<LinkAndLabel> asActionLinks(
             final ScalarModel scalarModel,
-            final List<ObjectAction> associatedActions) {
+            final Stream<ObjectAction> associatedActions) {
 
         final EntityModel parentEntityModel = scalarModel.getParentUiModel();
         return asActionLinksForAdditionalLinksPanel(parentEntityModel, associatedActions, scalarModel);
     }
 
-    public static LinkAndLabel asActionLink(final ScalarModel scalarModel, final ObjectAction inlineActionIfAny) {
-        if(inlineActionIfAny == null) {
-            return null;
-        }
-        return asActionLinks(scalarModel, Collections.singletonList(inlineActionIfAny)).get(0);
+    public static Stream<LinkAndLabel> asActionLink(
+            final ScalarModel scalarModel,
+            final ObjectAction inlineAction) {
+        return asActionLinks(scalarModel, Stream.of(inlineAction));
     }
 
     /**
-     * Converts an {@link org.apache.isis.viewer.wicket.model.models.EntityModel} and a (subset of its) {@link ObjectAction}s into a
+     * Converts an {@link org.apache.isis.viewer.wicket.model.models.EntityModel} and a (subset of its)
+     * {@link ObjectAction}s into a
      * list of {@link org.apache.isis.viewer.wicket.model.links.LinkAndLabel}s intended to be passed
      * to the {@link AdditionalLinksPanel}.
      *
@@ -60,32 +57,28 @@ public final class LinkAndLabelUtil {
      *     (for invisible actions) will be discarded.
      * </p>
      */
-    public static List<LinkAndLabel> asActionLinksForAdditionalLinksPanel(
+    public static Stream<LinkAndLabel> asActionLinksForAdditionalLinksPanel(
             final EntityModel parentEntityModel,
-            final List<ObjectAction> objectActions,
+            final Stream<ObjectAction> objectActions,
             final ScalarModel scalarModelIfAny) {
 
         return asActionLinksForAdditionalLinksPanel(parentEntityModel, objectActions, scalarModelIfAny, null);
     }
 
-    public static List<LinkAndLabel> asActionLinksForAdditionalLinksPanel(
+    public static Stream<LinkAndLabel> asActionLinksForAdditionalLinksPanel(
             final EntityModel parentEntityModel,
-            final List<ObjectAction> objectActions,
+            final Stream<ObjectAction> objectActions,
             final ScalarModel scalarModelIfAny,
             final ToggledMementosProvider toggledMementosProviderIfAny) {
 
         val actionLinkFactory = new EntityActionLinkFactory(
-                AdditionalLinksPanel.ID_ADDITIONAL_LINK, 
-                parentEntityModel, 
+                AdditionalLinksPanel.ID_ADDITIONAL_LINK,
+                parentEntityModel,
                 scalarModelIfAny,
                 toggledMementosProviderIfAny);
-        
-        val named = (String)null;
-        
-        return _NullSafe.stream(objectActions)
-                .map(objectAction->actionLinkFactory.newActionLink(objectAction, named))
-                .filter(_NullSafe::isPresent)
-                .collect(Collectors.toList());
+
+        return objectActions
+                .map(objectAction->actionLinkFactory.newActionLink(objectAction, /*named*/null));
     }
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/AssociatedWithActionsHelper.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/AssociatedWithActionsHelper.java
deleted file mode 100644
index 2dff2bf..0000000
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/AssociatedWithActionsHelper.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-package org.apache.isis.viewer.wicket.ui.components.collection;
-
-import java.io.Serializable;
-
-import org.apache.isis.commons.collections.Can;
-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;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
-import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
-import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
-import org.apache.isis.viewer.wicket.ui.components.collection.bulk.BulkActionsProvider;
-
-import lombok.val;
-
-/**
- * See also {@link BulkActionsProvider}.
- */
-public class AssociatedWithActionsHelper implements Serializable {
-    private static final long serialVersionUID = 1L;
-
-    private final EntityCollectionModel collectionModel;
-
-    public AssociatedWithActionsHelper(final EntityCollectionModel collectionModel) {
-        this.collectionModel = collectionModel;
-    }
-
-    //TODO refactor: move to EntityCollectionModel
-    public Can<ObjectAction> getAssociatedActions(final SpecificationLoader specLoader) {
-
-        if(collectionModel.isStandalone()) {
-            return Can.empty();
-        }
-        final OneToManyAssociation collection = collectionModel.getCollectionMemento()
-                .getCollection(specLoader);
-
-        return getObjectSpecification()
-                .streamRuntimeActions(MixedIn.INCLUDED)
-                .filter(ObjectAction.Predicates.associatedWithAndWithCollectionParameterFor(collection))
-                .collect(Can.toCan());
-    }
-
-    // -- HELPER
-
-    //TODO refactor: move to EntityCollectionModel
-    private ObjectSpecification getObjectSpecification() {
-        val parentMemento = collectionModel.getParentObjectAdapterMemento();
-        val parentAdapter = collectionModel.getCommonContext().reconstructObject(parentMemento);
-        return parentAdapter.getSpecification();
-    }
-
-}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
index 1728f5d..acd4260 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
@@ -28,15 +28,11 @@ import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
 import org.apache.wicket.markup.html.basic.Label;
 
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
 import org.apache.isis.viewer.wicket.model.common.OnSelectionHandler;
-import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelParented;
 import org.apache.isis.viewer.wicket.model.models.ToggledMementosProvider;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelUtil;
@@ -57,7 +53,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel
  * of) {@link ScalarPanelAbstract}.
  */
 public class CollectionPanel
-extends PanelAbstract<List<ManagedObject>, EntityCollectionModel>
+extends PanelAbstract<List<ManagedObject>, EntityCollectionModelParented>
 implements CollectionSelectorProvider, BulkActionsProvider {
 
     private static final long serialVersionUID = 1L;
@@ -68,33 +64,25 @@ implements CollectionSelectorProvider, BulkActionsProvider {
 
     private Label label;
 
-    private final AssociatedWithActionsHelper associatedWithActionsHelper;
-
     public CollectionPanel(
             final String id,
-            final EntityCollectionModel collectionModel) {
+            final EntityCollectionModelParented collectionModel) {
         super(id, collectionModel);
 
-        final List<LinkAndLabel> entityActionLinks = _Lists.newArrayList();
-
-        final OneToManyAssociation otma = collectionModel.getCollectionMemento().getCollection(collectionModel.getSpecificationLoader());
-        final EntityModel entityModel = collectionModel.getEntityModel();
-        val adapter = entityModel.getManagedObject();
-
-        final List<ObjectAction> associatedActions =
-                ObjectAction.Util.findForAssociation(adapter, otma);
+        val associatedActions = collectionModel.getAssociatedActions();
 
-        associatedWithActionsHelper = new AssociatedWithActionsHelper(collectionModel);
-
-        final ToggledMementosProvider toggledMementosProvider =
+        val toggledMementosProvider =
                 new MyToggledMementosProvider(collectionModel, this, this);
 
-        entityActionLinks.addAll(
-                LinkAndLabelUtil
+        val entityActionLinks = LinkAndLabelUtil
                 .asActionLinksForAdditionalLinksPanel(
-                        entityModel, associatedActions, null, toggledMementosProvider));
+                        collectionModel.getEntityModel(),
+                        associatedActions.stream(),
+                        null,
+                        toggledMementosProvider)
+                .collect(Can.toCan());
 
-        collectionModel.addLinkAndLabels(entityActionLinks);
+        collectionModel.setLinkAndLabels(entityActionLinks);
 
     }
 
@@ -138,11 +126,10 @@ implements CollectionSelectorProvider, BulkActionsProvider {
     public ObjectAdapterToggleboxColumn getToggleboxColumn() {
 
         if(toggleboxColumn == null) {
-            val associatedActions =
-                    associatedWithActionsHelper.getAssociatedActions(getSpecificationLoader());
-
             val entityCollectionModel = getModel();
-            if(associatedActions.isEmpty() || entityCollectionModel.isStandalone()) {
+
+            val associatedActions = entityCollectionModel.getAssociatedActions();
+            if(associatedActions.isEmpty()) {
                 return null;
             }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java
index 7f6e129..c39643d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorHelper.java
@@ -22,6 +22,9 @@ package org.apache.isis.viewer.wicket.ui.components.collection.selector;
 import java.io.Serializable;
 import java.util.List;
 import java.util.Objects;
+import java.util.Optional;
+
+import javax.annotation.Nullable;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
@@ -33,7 +36,7 @@ import org.apache.isis.core.metamodel.facets.collections.collection.defaultview.
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.viewer.wicket.model.hints.UiHintContainer;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelParented;
 import org.apache.isis.viewer.wicket.model.util.ComponentHintKey;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
@@ -42,37 +45,39 @@ import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.multiple.CollectionContentsMultipleViewsPanelFactory;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.unresolved.CollectionContentsHiddenPanelFactory;
 
+import lombok.val;
+
 public class CollectionSelectorHelper implements Serializable {
 
     private static final long serialVersionUID = 1L;
 
-    static final String UIHINT_EVENT_VIEW_KEY = EntityCollectionModel.HINT_KEY_SELECTED_ITEM;
+    static final String UIHINT_EVENT_VIEW_KEY = EntityCollectionModelParented.HINT_KEY_SELECTED_ITEM;
 
-    private final EntityCollectionModel model;
+    private final EntityCollectionModel collectionModel;
 
     private final List<ComponentFactory> componentFactories;
     private final ComponentHintKey componentHintKey;
 
     public CollectionSelectorHelper(
-            final EntityCollectionModel model,
+            final EntityCollectionModel collectionModel,
             final ComponentFactoryRegistry componentFactoryRegistry) {
-        this(model, componentFactoryRegistry, ComponentHintKey.noop());
+        this(collectionModel, componentFactoryRegistry, ComponentHintKey.noop());
     }
 
     public CollectionSelectorHelper(
-            final EntityCollectionModel model,
+            final EntityCollectionModel collectionModel,
             final ComponentFactoryRegistry componentFactoryRegistry,
             final ComponentHintKey componentHintKey) {
-        this.model = model;
+        this.collectionModel = collectionModel;
         this.componentFactories = locateComponentFactories(componentFactoryRegistry);
-        this.componentHintKey = componentHintKey != null 
-                ? componentHintKey 
+        this.componentHintKey = componentHintKey != null
+                ? componentHintKey
                 : ComponentHintKey.noop();
     }
 
     private List<ComponentFactory> locateComponentFactories(ComponentFactoryRegistry componentFactoryRegistry) {
-        final List<ComponentFactory> componentFactories = componentFactoryRegistry.findComponentFactories(ComponentType.COLLECTION_CONTENTS, model);
-        final List<ComponentFactory> otherFactories = _Lists.filter(componentFactories, 
+        final List<ComponentFactory> componentFactories = componentFactoryRegistry.findComponentFactories(ComponentType.COLLECTION_CONTENTS, collectionModel);
+        final List<ComponentFactory> otherFactories = _Lists.filter(componentFactories,
                 (final ComponentFactory input) ->
         input.getClass() != CollectionContentsMultipleViewsPanelFactory.class);
         return ordered(otherFactories);
@@ -118,7 +123,10 @@ public class CollectionSelectorHelper implements Serializable {
         }
 
         // else grid layout hint
-        final CollectionLayoutData layoutData = this.model.getLayoutData();
+        final CollectionLayoutData layoutData = toParentedEntityCollectionModel(collectionModel)
+                .map(EntityCollectionModelParented::getLayoutData)
+                .orElse(null);
+
         if(layoutData != null) {
             final String defaultView = layoutData.getDefaultView();
             if(defaultView != null) {
@@ -127,8 +135,8 @@ public class CollectionSelectorHelper implements Serializable {
         }
 
         // else @CollectionLayout#defaultView attribute
-        if (hasDefaultViewFacet(model)) {
-            DefaultViewFacet defaultViewFacet = model.getCollectionMemento().getCollection(model.getSpecificationLoader()).getFacet(DefaultViewFacet.class);
+        if (hasDefaultViewFacet(collectionModel)) {
+            DefaultViewFacet defaultViewFacet = collectionModel.getMetaModel().getFacet(DefaultViewFacet.class);
             for (ComponentFactory componentFactory : componentFactories) {
                 final String componentName = componentFactory.getName();
                 final String viewName = defaultViewFacet.value();
@@ -139,16 +147,14 @@ public class CollectionSelectorHelper implements Serializable {
         }
 
         // else honour @CollectionLayout#renderEagerly
-        return hasRenderEagerlyFacet(model) || model.isStandalone()
+        return hasRenderEagerlyFacet(collectionModel) || collectionModel.isStandalone()
                 ? CollectionContentsAsAjaxTablePanelFactory.NAME
-                        : CollectionContentsHiddenPanelFactory.NAME;
+                : CollectionContentsHiddenPanelFactory.NAME;
 
     }
 
     private Bookmark bookmarkHintIfAny() {
-        final EntityModel entityModel = this.model.getEntityModel();
-        return entityModel != null
-                ? entityModel.asHintingBookmarkIfSupported(): null;
+        return collectionModel.asHintingBookmarkIfSupported();
     }
 
     private static List<ComponentFactory> ordered(List<ComponentFactory> componentFactories) {
@@ -177,60 +183,39 @@ public class CollectionSelectorHelper implements Serializable {
     }
 
     private static UiHintContainer getUiHintContainer(final Component component) {
-        return UiHintContainer.Util.hintContainerOf(component, EntityCollectionModel.class);
+        return UiHintContainer.Util.hintContainerOf(component, EntityCollectionModelParented.class);
     }
 
     private static boolean hasRenderEagerlyFacet(IModel<?> model) {
-        final EntityCollectionModel entityCollectionModel = toEntityCollectionModel(model);
-        if (entityCollectionModel == null) {
-            return false;
-        }
-
-        final OneToManyAssociation collection =
-                entityCollectionModel.getCollectionMemento().getCollection(entityCollectionModel.getSpecificationLoader());
-        return renderEagerly(collection);
+        return toParentedEntityCollectionModel(model)
+        .map(EntityCollectionModelParented::getMetaModel)
+        .map(CollectionSelectorHelper::isRenderEagerly)
+        .orElse(false);
     }
 
-    private static boolean renderEagerly(final OneToManyAssociation otma) {
-        final DefaultViewFacet defaultViewFacet = otma.getFacet(DefaultViewFacet.class);
+    private static boolean isRenderEagerly(final OneToManyAssociation collectionMetaModel) {
+        final DefaultViewFacet defaultViewFacet = collectionMetaModel.getFacet(DefaultViewFacet.class);
         return defaultViewFacet != null && Objects.equals(defaultViewFacet.value(), "table");
     }
 
 
     private static boolean hasDefaultViewFacet(IModel<?> model) {
-        final EntityCollectionModel entityCollectionModel = toEntityCollectionModel(model);
+        val entityCollectionModel = toParentedEntityCollectionModel(model).orElse(null);
         if (entityCollectionModel == null) {
             return false;
         }
-
-        final OneToManyAssociation collection =
-                entityCollectionModel.getCollectionMemento().getCollection(entityCollectionModel.getSpecificationLoader());
+        final OneToManyAssociation collection = entityCollectionModel.getMetaModel();
         DefaultViewFacet defaultViewFacet = collection.getFacet(DefaultViewFacet.class);
         return defaultViewFacet != null;
     }
 
-    private static EntityCollectionModel toEntityCollectionModel(IModel<?> model) {
-        if (!(model instanceof EntityCollectionModel)) {
-            return null;
-        }
-
-        final EntityCollectionModel entityCollectionModel = (EntityCollectionModel) model;
-        if (!entityCollectionModel.isParented()) {
-            return null;
-        }
-
-        return entityCollectionModel;
-    }
-
     public ComponentFactory find(final String selected) {
         ComponentFactory componentFactory = doFind(selected);
         if (componentFactory != null) {
             return componentFactory;
         }
 
-        final EntityCollectionModel entityCollectionModel = model;
-        final String fallback;
-        fallback = entityCollectionModel.isParented()
+        final String fallback = collectionModel.isParented()
                 ? CollectionContentsHiddenPanelFactory.NAME
                 : CollectionContentsAsAjaxTablePanelFactory.NAME;
         componentFactory = doFind(fallback);
@@ -262,6 +247,15 @@ public class CollectionSelectorHelper implements Serializable {
         return 0;
     }
 
+    // -- HELPER
+
+    private static Optional<EntityCollectionModelParented> toParentedEntityCollectionModel(
+            final @Nullable IModel<?> model) {
+        if (model instanceof EntityCollectionModelParented) {
+            return Optional.of((EntityCollectionModelParented) model);
+        }
+        return Optional.empty();
+    }
 
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java
index e969441..bc6b97f 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/selector/CollectionSelectorPanel.java
@@ -39,7 +39,6 @@ import org.apache.isis.core.metamodel.commons.StringExtensions;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.viewer.wicket.model.hints.IsisSelectorEvent;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.util.ComponentHintKey;
 import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
@@ -53,7 +52,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
  * {@link org.apache.isis.viewer.wicket.ui.ComponentType#COLLECTION_CONTENTS} with a backing
  * {@link org.apache.isis.viewer.wicket.model.models.EntityCollectionModel}.
  */
-public class CollectionSelectorPanel 
+public class CollectionSelectorPanel
 extends PanelAbstract<List<ManagedObject>, EntityCollectionModel> {
 
     private static final long serialVersionUID = 1L;
@@ -76,7 +75,7 @@ extends PanelAbstract<List<ManagedObject>, EntityCollectionModel> {
     public CollectionSelectorPanel(
             final String id,
             final EntityCollectionModel model) {
-        this(id, model, ComponentHintKey.<String>noop());
+        this(id, model, ComponentHintKey.noop());
     }
 
     public CollectionSelectorPanel(
@@ -150,11 +149,7 @@ extends PanelAbstract<List<ManagedObject>, EntityCollectionModel> {
                         }
 
                         Bookmark domainObjectBookmarkIfAny() {
-                            final EntityCollectionModel entityCollectionModel = CollectionSelectorPanel.this.getModel();
-                            final EntityModel entityModel = entityCollectionModel.getEntityModel();
-                            return entityModel != null
-                                    ? entityModel.asHintingBookmarkIfSupported()
-                                    : null;
+                            return CollectionSelectorPanel.this.getModel().asHintingBookmarkIfSupported();
                         }
 
                         @Override
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
index 2651e88..52c23e7 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -45,13 +45,13 @@ import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
 import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.facets.object.grid.GridFacet;
+import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 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.ObjectAssociation;
 import org.apache.isis.core.runtime.memento.ObjectMemento;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.components.collection.bulk.BulkActionsProvider;
 import org.apache.isis.viewer.wicket.ui.components.collection.count.CollectionCountProvider;
 import org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns.ObjectAdapterPropertyColumn;
@@ -106,7 +106,7 @@ implements CollectionCountProvider {
             bulkActionsProvider.configureBulkActions(toggleboxColumn);
         }
 
-        final EntityCollectionModel collectionModel = getModel();
+        val collectionModel = getModel();
         addTitleColumn(
                 columns,
                 collectionModel.getParentObjectAdapterMemento(),
@@ -254,8 +254,8 @@ implements CollectionCountProvider {
 //        val parentObject = Optional.ofNullable(collectionModel.getParentObjectAdapterMemento())
 //                .map(getCommonContext()::reconstructObject);
 
-        val parentObject = Optional.ofNullable(collectionModel.getEntityModel())
-                .map(EntityModel::getManagedObject);
+        final Optional<ManagedObject> parentObject = collectionModel.getManagedCollection()
+                .map(ManagedCollection::getOwner);
 
         tableColumnOrderServices.stream()
         .map(tableColumnOrderService->
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java
index 6848b33..fe10d4a 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterPropertyColumn.java
@@ -62,7 +62,7 @@ public final class ObjectAdapterPropertyColumn extends ColumnAbstract<ManagedObj
     private final String describedAs;
 
     public ObjectAdapterPropertyColumn(
-            IsisAppCommonContext commonContext, 
+            IsisAppCommonContext commonContext,
             EntityCollectionModel.Variant collectionVariant,
             IModel<String> columnNameModel,
             String sortProperty,
@@ -70,7 +70,7 @@ public final class ObjectAdapterPropertyColumn extends ColumnAbstract<ManagedObj
             boolean escaped,
             String parentTypeName,
             String describedAs) {
-        
+
         super(commonContext, columnNameModel, sortProperty);
         this.collectionVariant = collectionVariant;
         this.propertyExpression = propertyName;
@@ -99,10 +99,10 @@ public final class ObjectAdapterPropertyColumn extends ColumnAbstract<ManagedObj
 
     @Override
     public void populateItem(
-            final Item<ICellPopulator<ManagedObject>> cellItem, 
-            final String componentId, 
+            final Item<ICellPopulator<ManagedObject>> cellItem,
+            final String componentId,
             final IModel<ManagedObject> rowModel) {
-        
+
         final Component component = createComponent(componentId, rowModel);
         cellItem.add(component);
     }
@@ -114,7 +114,8 @@ public final class ObjectAdapterPropertyColumn extends ColumnAbstract<ManagedObj
         final OneToOneAssociation property = (OneToOneAssociation) adapter.getSpecification().getAssociationElseFail(propertyExpression);
         final PropertyMemento pm = new PropertyMemento(property);
 
-        final ScalarModel scalarModel = entityModel.getPropertyModel(pm, EntityModel.Mode.VIEW, collectionVariant.renderingHint());
+        final ScalarModel scalarModel = entityModel
+                .getPropertyModel(pm, EntityModel.Mode.VIEW, collectionVariant.getColumnRenderingHint());
 
         final ComponentFactory componentFactory = findComponentFactory(ComponentType.SCALAR_NAME_AND_VALUE, scalarModel);
         return componentFactory.createComponent(id, scalarModel);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
index 7229b22..7093c2d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable.columns;
 
+import javax.annotation.Nullable;
+
 import org.apache.wicket.Component;
 import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
 import org.apache.wicket.markup.repeater.Item;
@@ -41,49 +43,53 @@ public class ObjectAdapterTitleColumn extends ColumnAbstract<ManagedObject> {
     private static final long serialVersionUID = 1L;
     private final ObjectMemento parentAdapterMementoIfAny;
 
-    private static String columnName(final ObjectMemento parentAdapterMementoIfAny, final int maxTitleLength) {
-        if(maxTitleLength == 0) {
-            return "";
-        }
-        return (parentAdapterMementoIfAny != null? "Related ":"") + "Object";
-    }
-
     public ObjectAdapterTitleColumn(
-            IsisAppCommonContext commonContext, 
-            ObjectMemento parentAdapterMementoIfAny, 
+            IsisAppCommonContext commonContext,
+            ObjectMemento parentAdapterMementoIfAny,
             int maxTitleLength) {
-        
+
         super(commonContext, columnName(parentAdapterMementoIfAny, maxTitleLength)); // i18n
         this.parentAdapterMementoIfAny = parentAdapterMementoIfAny;
     }
 
     @Override
     public void populateItem(
-            final Item<ICellPopulator<ManagedObject>> cellItem, 
-            final String componentId, 
+            final Item<ICellPopulator<ManagedObject>> cellItem,
+            final String componentId,
             final IModel<ManagedObject> rowModel) {
-        
+
         final Component component = createComponent(componentId, rowModel);
         cellItem.add(component);
         cellItem.add(new CssClassAppender("title-column"));
     }
 
+    // -- HELPER
+
+    private static String columnName(
+            final @Nullable ObjectMemento parentAdapterMementoIfAny,
+            final int maxTitleLength) {
+        if(maxTitleLength == 0) {
+            return "";
+        }
+        return (parentAdapterMementoIfAny != null? "Related ":"") + "Object";
+    }
+
     private Component createComponent(final String id, final IModel<ManagedObject> rowModel) {
         val adapter = rowModel.getObject();
-        
+
         if(ManagedObjects.isValue(adapter)) {
             val valueModel = new ValueModel(super.getCommonContext(), adapter);
-            
+
             val componentFactory = findComponentFactory(ComponentType.VALUE, valueModel);
             return componentFactory.createComponent(id, valueModel);
         }
-        
+
         val entityModel = EntityModel.ofAdapter(super.getCommonContext(), adapter);
         entityModel.setRenderingHint(parentAdapterMementoIfAny != null
                 ? RenderingHint.PARENTED_TITLE_COLUMN
-                        : RenderingHint.STANDALONE_TITLE_COLUMN);
+                : RenderingHint.STANDALONE_TITLE_COLUMN);
         entityModel.setContextAdapterIfAny(parentAdapterMementoIfAny);
-        
+
         // will use EntityLinkSimplePanelFactory as model is an EntityModel
         val componentFactory = findComponentFactory(ComponentType.ENTITY_LINK, entityModel);
         return componentFactory.createComponent(id, entityModel);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/multiple/CollectionContentsMultipleViewsPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/multiple/CollectionContentsMultipleViewsPanel.java
index 2901d11..aa9aab4 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/multiple/CollectionContentsMultipleViewsPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/multiple/CollectionContentsMultipleViewsPanel.java
@@ -29,7 +29,8 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.viewer.wicket.model.hints.IsisEnvelopeEvent;
 import org.apache.isis.viewer.wicket.model.hints.IsisSelectorEvent;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
-import org.apache.isis.viewer.wicket.model.models.EntityModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelDummy;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelParented;
 import org.apache.isis.viewer.wicket.model.util.ComponentHintKey;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
@@ -40,20 +41,20 @@ import org.apache.isis.viewer.wicket.ui.components.collection.selector.Collectio
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 
 /**
- * Subscribes to events generated by 
- * {@link org.apache.isis.viewer.wicket.ui.components.collection.selector.CollectionSelectorPanel}, 
+ * Subscribes to events generated by
+ * {@link org.apache.isis.viewer.wicket.ui.components.collection.selector.CollectionSelectorPanel},
  * rendering the appropriate {@link ComponentType#COLLECTION_CONTENTS}
  * view for a backing {@link EntityCollectionModel}.
  */
 public class CollectionContentsMultipleViewsPanel
-extends PanelAbstract<List<ManagedObject>, EntityCollectionModel> 
+extends PanelAbstract<List<ManagedObject>, EntityCollectionModel>
 implements CollectionCountProvider {
 
     private static final long serialVersionUID = 1L;
 
     private static final int MAX_NUM_UNDERLYING_VIEWS = 10;
 
-    private static final String UIHINT_VIEW = EntityCollectionModel.HINT_KEY_SELECTED_ITEM;
+    private static final String UIHINT_VIEW = EntityCollectionModelParented.HINT_KEY_SELECTED_ITEM;
 
     private final String underlyingIdPrefix;
     private final CollectionSelectorHelper selectorHelper;
@@ -68,15 +69,14 @@ implements CollectionCountProvider {
         super(id, model);
 
         this.underlyingIdPrefix = ComponentType.COLLECTION_CONTENTS.toString();
-        final EntityModel entityModel = model.getEntityModel();
 
         final ComponentHintKey selectedItemSessionAttribute =
-                entityModel != null
-                ? ComponentHintKey.create(super.getCommonContext(), this, EntityCollectionModel.HINT_KEY_SELECTED_ITEM)
-                        : null;
+                model.isParented()
+                    ? ComponentHintKey.create(super.getCommonContext(), this, UIHINT_VIEW)
+                    : null;
 
-                selectorHelper = new CollectionSelectorHelper(
-                        model, getComponentFactoryRegistry(), selectedItemSessionAttribute);
+        selectorHelper = new CollectionSelectorHelper(
+                model, getComponentFactoryRegistry(), selectedItemSessionAttribute);
     }
 
     /**
@@ -106,12 +106,14 @@ implements CollectionCountProvider {
         int i = 0;
         int selectedIdx = 0;
         underlyingViews = new Component[MAX_NUM_UNDERLYING_VIEWS];
-        final EntityCollectionModel emptyModel = model.asDummy();
+
+        final EntityCollectionModel emptyModel = EntityCollectionModelDummy.forCollectionModel(model);
         for (ComponentFactory componentFactory : componentFactories) {
             final String underlyingId = underlyingIdPrefix + "-" + i;
 
             final boolean isSelected = selected.equals(componentFactory.getName());
-            final Component underlyingView = componentFactory.createComponent(underlyingId, isSelected ? model : emptyModel);
+            final Component underlyingView = componentFactory
+                    .createComponent(underlyingId, isSelected ? model : emptyModel);
             if(isSelected) {
                 selectedIdx = i;
             }
@@ -162,7 +164,7 @@ implements CollectionCountProvider {
 
         int underlyingViewNum = selectorHelper.lookup(selectedView);
 
-        final EntityCollectionModel dummyModel = getModel().asDummy();
+        final EntityCollectionModel dummyModel = EntityCollectionModelDummy.forCollectionModel(getModel());
         for(int i=0; i<MAX_NUM_UNDERLYING_VIEWS; i++) {
             final Component component = underlyingViews[i];
             if(component == null) {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java
index 397a0d1..fe55e99 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/collection/EntityCollectionPanel.java
@@ -30,14 +30,15 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.model.Model;
 
 import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelParented;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.util.ComponentHintKey;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
@@ -57,8 +58,8 @@ import lombok.val;
  * {@link PanelAbstract Panel} representing the properties of an entity, as per
  * the provided {@link EntityModel}.
  */
-public class EntityCollectionPanel 
-extends PanelAbstract<ManagedObject, EntityModel> 
+public class EntityCollectionPanel
+extends PanelAbstract<ManagedObject, EntityModel>
 implements HasDynamicallyVisibleContent {
 
     private static final long serialVersionUID = 1L;
@@ -79,7 +80,7 @@ implements HasDynamicallyVisibleContent {
     public EntityCollectionPanel(final String id, final EntityModel entityModel) {
         super(id, entityModel);
 
-        selectedItemHintKey = ComponentHintKey.create(super.getCommonContext(), getSelectorDropdownPanel(), EntityCollectionModel.HINT_KEY_SELECTED_ITEM);
+        selectedItemHintKey = ComponentHintKey.create(super.getCommonContext(), getSelectorDropdownPanel(), EntityCollectionModelParented.HINT_KEY_SELECTED_ITEM);
         div = buildGui();
     }
 
@@ -106,46 +107,47 @@ implements HasDynamicallyVisibleContent {
     private WebMarkupContainer buildGui() {
         final WebMarkupContainer div = new WebMarkupContainer(ID_COLLECTION_GROUP);
 
-        final EntityCollectionModel entityCollectionModel = EntityCollectionModel.createParented(getModel());
-        div.setMarkupId("collection-" + entityCollectionModel.getLayoutData().getId());
+        val collectionModel = EntityCollectionModel.createParented(getModel());
+        div.setMarkupId("collection-" + collectionModel.getLayoutData().getId());
 
-        CssClassAppender.appendCssClassTo(div, entityCollectionModel.getCollectionMemento().getId());
-        CssClassAppender.appendCssClassTo(div, entityCollectionModel.getTypeOfSpecification().getFullIdentifier().replace('.','-'));
+        val collectionMetaModel = collectionModel.getMetaModel();
+
+        CssClassAppender.appendCssClassTo(div, collectionModel.getIdentifier().getMemberName());
+        CssClassAppender.appendCssClassTo(div, collectionModel.getTypeOfSpecification().getFullIdentifier().replace('.','-'));
 
-        final OneToManyAssociation association = entityCollectionModel.getCollectionMemento().getCollection(
-                entityCollectionModel.getSpecificationLoader());
         val objectAdapter = getModel().getObject();
-        final Consent visibility = association.isVisible(objectAdapter, InteractionInitiatedBy.USER, Where.OBJECT_FORMS);
+        final Consent visibility = collectionMetaModel
+                .isVisible(objectAdapter, InteractionInitiatedBy.USER, Where.OBJECT_FORMS);
 
         if(visibility.isAllowed()) {
 
             visible = true;
 
-            final CssClassFacet facet = association.getFacet(CssClassFacet.class);
+            final CssClassFacet facet = collectionMetaModel.getFacet(CssClassFacet.class);
             if(facet != null) {
                 final String cssClass = facet.cssClass(objectAdapter);
                 CssClassAppender.appendCssClassTo(div, cssClass);
             }
 
-            final CollectionPanel collectionPanel = newCollectionModel(ID_COLLECTION, entityCollectionModel);
+            final CollectionPanel collectionPanel = newCollectionModel(ID_COLLECTION, collectionModel);
             div.addOrReplace(collectionPanel);
 
 
-            Label labelComponent = collectionPanel.createLabel(ID_COLLECTION_NAME, association.getName());
-            final NamedFacet namedFacet = association.getFacet(NamedFacet.class);
+            Label labelComponent = collectionPanel.createLabel(ID_COLLECTION_NAME, collectionMetaModel.getName());
+            final NamedFacet namedFacet = collectionMetaModel.getFacet(NamedFacet.class);
             labelComponent.setEscapeModelStrings(namedFacet == null || namedFacet.escaped());
             div.add(labelComponent);
 
-            final String description = association.getDescription();
+            final String description = collectionMetaModel.getDescription();
             if(description != null) {
                 Tooltips.addTooltip(labelComponent, description);
             }
 
-            final List<LinkAndLabel> links = entityCollectionModel.getLinks();
-            AdditionalLinksPanel.addAdditionalLinks (div,ID_ADDITIONAL_LINKS, links, AdditionalLinksPanel.Style.INLINE_LIST);
+            final Can<LinkAndLabel> links = collectionModel.getLinks();
+            AdditionalLinksPanel.addAdditionalLinks(div,ID_ADDITIONAL_LINKS, links, AdditionalLinksPanel.Style.INLINE_LIST);
 
             final CollectionSelectorHelper selectorHelper =
-                    new CollectionSelectorHelper(entityCollectionModel, getComponentFactoryRegistry(),
+                    new CollectionSelectorHelper(collectionModel, getComponentFactoryRegistry(),
                             selectedItemHintKey);
 
             final List<ComponentFactory> componentFactories = selectorHelper.getComponentFactories();
@@ -154,7 +156,7 @@ implements HasDynamicallyVisibleContent {
                 permanentlyHide(ID_SELECTOR_DROPDOWN);
             } else {
                 selectorDropdownPanel = new CollectionSelectorPanel(ID_SELECTOR_DROPDOWN,
-                        entityCollectionModel, selectedItemHintKey);
+                        collectionModel, selectedItemHintKey);
 
                 final Model<ComponentFactory> componentFactoryModel = new Model<>();
 
@@ -172,7 +174,7 @@ implements HasDynamicallyVisibleContent {
         return div;
     }
 
-    protected CollectionPanel newCollectionModel(String id, EntityCollectionModel entityCollectionModel) {
+    protected CollectionPanel newCollectionModel(String id, EntityCollectionModelParented entityCollectionModel) {
         return new CollectionPanel(id, entityCollectionModel);
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java
index ab21491..f3f0b24 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/fieldset/PropertyGroup.java
@@ -20,6 +20,7 @@ package org.apache.isis.viewer.wicket.ui.components.entity.fieldset;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 import org.apache.wicket.Component;
@@ -32,6 +33,7 @@ import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.layout.component.FieldSet;
 import org.apache.isis.applib.layout.component.PropertyLayoutData;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -77,12 +79,12 @@ public class PropertyGroup extends PanelAbstract<ManagedObject, EntityModel> imp
 
         // the UI is only ever built once.
         childComponents = buildGui();
-        childScalarPanelAbstract2s = 
+        childScalarPanelAbstract2s =
                 _NullSafe.stream(childComponents)
                 .filter(ScalarPanelAbstract.class::isInstance)
                 .map(ScalarPanelAbstract.class::cast)
                 .collect(Collectors.toList());
-                
+
     }
 
     @Override
@@ -114,7 +116,7 @@ public class PropertyGroup extends PanelAbstract<ManagedObject, EntityModel> imp
             final WebMarkupContainer propertyRvContainer = new WebMarkupContainer(propertyRv.newChildId());
             propertyRv.addOrReplace(propertyRvContainer);
             final Component component = addPropertyToForm(getModel(), (OneToOneAssociation) association,
-                    propertyRvContainer, memberGroupActions);
+                    propertyRvContainer, memberGroupActions::add);
             childComponents.add(component);
         }
 
@@ -124,10 +126,14 @@ public class PropertyGroup extends PanelAbstract<ManagedObject, EntityModel> imp
             panelHeading.setVisibilityAllowed(false);
         } else {
             panelHeading.addOrReplace(new Label(ID_MEMBER_GROUP_NAME, groupName));
-            final List<LinkAndLabel> actionsPanel = LinkAndLabel
-                    .positioned(memberGroupActions, ActionLayout.Position.PANEL);
-            final List<LinkAndLabel> actionsPanelDropDown = LinkAndLabel
-                    .positioned(memberGroupActions, ActionLayout.Position.PANEL_DROPDOWN);
+            final Can<LinkAndLabel> actionsPanel = memberGroupActions
+                    .stream()
+                    .filter(LinkAndLabel.positioned(ActionLayout.Position.PANEL))
+                    .collect(Can.toCan());
+            final Can<LinkAndLabel> actionsPanelDropDown = memberGroupActions
+                    .stream()
+                    .filter(LinkAndLabel.positioned(ActionLayout.Position.PANEL_DROPDOWN))
+                    .collect(Can.toCan());
 
             AdditionalLinksPanel.addAdditionalLinks(
                     panelHeading, ID_ASSOCIATED_ACTION_LINKS_PANEL,
@@ -172,7 +178,7 @@ public class PropertyGroup extends PanelAbstract<ManagedObject, EntityModel> imp
 
         val oas = _NullSafe.stream(properties)
                 .filter(propertyLayoutData -> propertyLayoutData.getMetadataError() == null)
-                .map(propertyLayoutData -> 
+                .map(propertyLayoutData ->
                     adapter.getSpecification()
                     .getAssociation(propertyLayoutData.getId())
                     .orElse(null)
@@ -189,7 +195,7 @@ public class PropertyGroup extends PanelAbstract<ManagedObject, EntityModel> imp
                     return true;
                 })
                 .collect(Collectors.toList());
-        
+
         return Collections.unmodifiableList(oas);
     }
 
@@ -197,7 +203,7 @@ public class PropertyGroup extends PanelAbstract<ManagedObject, EntityModel> imp
             final EntityModel entityModel,
             final OneToOneAssociation otoa,
             final WebMarkupContainer container,
-            final List<LinkAndLabel> entityActions) {
+            final Consumer<LinkAndLabel> onEntityAction) {
 
         final PropertyMemento pm = new PropertyMemento(otoa);
 
@@ -212,11 +218,10 @@ public class PropertyGroup extends PanelAbstract<ManagedObject, EntityModel> imp
         }
 
         val adapter = entityModel.getManagedObject();
-        final List<ObjectAction> associatedActions =
-                ObjectAction.Util.findForAssociation(adapter, otoa);
+        val associatedActions = ObjectAction.Util.findForAssociation(adapter, otoa);
 
-        entityActions.addAll(
-                LinkAndLabelUtil.asActionLinksForAdditionalLinksPanel(entityModel, associatedActions, null));
+        LinkAndLabelUtil.asActionLinksForAdditionalLinksPanel(entityModel, associatedActions, null)
+        .forEach(onEntityAction);
 
         return component;
     }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
index e7fa993..c60cdd0 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
@@ -19,13 +19,11 @@
 
 package org.apache.isis.viewer.wicket.ui.components.entity.header;
 
-import java.util.List;
-
 import org.apache.wicket.Component;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
@@ -40,7 +38,7 @@ import lombok.val;
  * {@link PanelAbstract Panel} representing the summary details (title, icon and
  * actions) of an entity, as per the provided {@link EntityModel}.
  */
-public class EntityHeaderPanel 
+public class EntityHeaderPanel
 extends PanelAbstract<ManagedObject, EntityModel> {
 
     private static final long serialVersionUID = 1L;
@@ -82,13 +80,14 @@ extends PanelAbstract<ManagedObject, EntityModel> {
         final EntityModel model = getModel();
         val adapter = model.getObject();
         if (adapter != null) {
-            final List<ObjectAction> topLevelActions = ObjectAction.Util
-                    .findTopLevel(adapter);
-
-            final List<LinkAndLabel> entityActionLinks = LinkAndLabelUtil
-                    .asActionLinksForAdditionalLinksPanel(model, topLevelActions, null);
-
-            AdditionalLinksPanel.addAdditionalLinks(this, ID_ENTITY_ACTIONS, entityActionLinks, AdditionalLinksPanel.Style.INLINE_LIST);
+            val topLevelActions = ObjectAction.Util.streamTopLevelActions(adapter);
+            val entityActionLinks = LinkAndLabelUtil
+                    .asActionLinksForAdditionalLinksPanel(model, topLevelActions, null)
+                    .collect(Can.toCan());
+
+            AdditionalLinksPanel
+                    .addAdditionalLinks(this, ID_ENTITY_ACTIONS, entityActionLinks,
+                            AdditionalLinksPanel.Style.INLINE_LIST);
         } else {
             permanentlyHide(ID_ENTITY_ACTIONS);
         }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java
index e2e2f8c..2162081 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java
@@ -33,6 +33,7 @@ import org.apache.isis.applib.layout.grid.bootstrap3.BS3Col;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3Row;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3Tab;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3TabGroup;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -53,8 +54,8 @@ import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
 import lombok.val;
 
-public class Col 
-extends PanelAbstract<ManagedObject, EntityModel> 
+public class Col
+extends PanelAbstract<ManagedObject, EntityModel>
 implements HasDynamicallyVisibleContent {
 
     private static final long serialVersionUID = 1L;
@@ -122,15 +123,16 @@ implements HasDynamicallyVisibleContent {
 
         // actions
         // (rendering depends on whether also showing the icon/title)
-        final List<ActionLayoutData> actionLayoutDatas = bs3Col.getActions();
-        val visibleActions = _NullSafe.stream(actionLayoutDatas)
-                .filter(actionLayoutData -> actionLayoutData.getMetadataError() == null)
-                .filter(_NullSafe::isPresent)
-                .map(actionLayoutData -> 
-                    getModel().getTypeOfSpecification().getAction(actionLayoutData.getId()).orElse(null)
-                )
-                .filter(_NullSafe::isPresent)
-                .collect(Collectors.toList());
+        final List<ActionLayoutData> actionLayoutDataList = bs3Col.getActions();
+
+        val visibleActions = _NullSafe.stream(actionLayoutDataList)
+        .filter(actionLayoutData -> actionLayoutData.getMetadataError() == null)
+        .filter(_NullSafe::isPresent)
+        .map(actionLayoutData ->
+            getModel().getTypeOfSpecification().getAction(actionLayoutData.getId()).orElse(null)
+        )
+        .filter(_NullSafe::isPresent);
+
         //
         // visibility needs to be determined at point of rendering, by ActionLink itself
         //
@@ -142,8 +144,9 @@ implements HasDynamicallyVisibleContent {
         //    }
         //})
 
-        final List<LinkAndLabel> entityActionLinks =
-                LinkAndLabelUtil.asActionLinksForAdditionalLinksPanel(getModel(), visibleActions, null);
+        final Can<LinkAndLabel> entityActionLinks = LinkAndLabelUtil
+        .asActionLinksForAdditionalLinksPanel(getModel(), visibleActions, null)
+        .collect(Can.toCan());
 
         if (!entityActionLinks.isEmpty()) {
             AdditionalLinksPanel.addAdditionalLinks(actionOwner, actionIdToUse, entityActionLinks, AdditionalLinksPanel.Style.INLINE_LIST);
@@ -172,12 +175,12 @@ implements HasDynamicallyVisibleContent {
         final List<BS3TabGroup> tabGroupsWithNonEmptyTabs =
                 _NullSafe.stream(bs3Col.getTabGroups())
                 .filter(_NullSafe::isPresent)
-                .filter(bs3TabGroup -> 
+                .filter(bs3TabGroup ->
                         _NullSafe.stream(bs3TabGroup.getTabs())
                                 .anyMatch(BS3Tab.Predicates.notEmpty())
                 )
                 .collect(Collectors.toList());
-        
+
         if(!tabGroupsWithNonEmptyTabs.isEmpty()) {
             final RepeatingViewWithDynamicallyVisibleContent tabGroupRv =
                     new RepeatingViewWithDynamicallyVisibleContent(ID_TAB_GROUPS);
@@ -220,12 +223,12 @@ implements HasDynamicallyVisibleContent {
 
 
         // fieldsets
-        final List<FieldSet> fieldSetsWithProperties = 
+        final List<FieldSet> fieldSetsWithProperties =
                 _NullSafe.stream(bs3Col.getFieldSets())
                 .filter(_NullSafe::isPresent)
                 .filter(fieldSet -> ! _NullSafe.isEmpty(fieldSet.getProperties()))
                 .collect(Collectors.toList());
-        
+
         if(!fieldSetsWithProperties.isEmpty()) {
             final RepeatingViewWithDynamicallyVisibleContent fieldSetRv =
                     new RepeatingViewWithDynamicallyVisibleContent(ID_FIELD_SETS);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
index 15cc4ed..411bc45 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
@@ -42,6 +42,8 @@ import org.apache.isis.applib.annotation.ActionLayout;
 import org.apache.isis.applib.annotation.PromptStyle;
 import org.apache.isis.applib.services.metamodel.BeanSort;
 import org.apache.isis.applib.services.metamodel.MetaModelService;
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._Refs;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.debug._Probe;
@@ -82,8 +84,8 @@ import lombok.val;
 import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
 
 
-public abstract class ScalarPanelAbstract 
-extends PanelAbstract<ManagedObject, ScalarModel> 
+public abstract class ScalarPanelAbstract
+extends PanelAbstract<ManagedObject, ScalarModel>
 implements ScalarModelSubscriber {
 
     private static final long serialVersionUID = 1L;
@@ -135,10 +137,10 @@ implements ScalarModelSubscriber {
                 onInitializeEditable();
             } else {
                 onInitializeReadonly(usabilityConsent.getReason());
-            }            
-        }; 
+            }
+        };
     }
-    
+
     /**
      *
      * @param argsAndConsents - the action being invoked
@@ -149,9 +151,9 @@ implements ScalarModelSubscriber {
     public Repaint updateIfNecessary(
             @NonNull final FormPendingParamUiModel argsAndConsents,
             @NonNull final Optional<AjaxRequestTarget> target) {
-        
+
         val argModel = argsAndConsents.getParamModel();
-        
+
         // visibility
         val visibilityConsent = argsAndConsents.getVisibilityConsent();
         val visibilityBefore = isVisible();
@@ -169,8 +171,8 @@ implements ScalarModelSubscriber {
         }
 
         val paramValue = argModel.getValue();
-        val valueChanged = !Objects.equals(scalarModel.getObject(), paramValue); 
-        
+        val valueChanged = !Objects.equals(scalarModel.getObject(), paramValue);
+
         if(valueChanged) {
             if(ManagedObjects.isNullOrUnspecifiedOrEmpty(paramValue)) {
                 scalarModel.setObject(null);
@@ -179,7 +181,7 @@ implements ScalarModelSubscriber {
             }
             scalarModel.clearPending();
         }
-        
+
 
         // repaint the entire form if visibility has changed
         if (!visibilityBefore || !visibilityAfter) {
@@ -274,7 +276,7 @@ implements ScalarModelSubscriber {
             postInit.run();
             postInit=null;
         } else {
-        
+
         final String disableReasonIfAny = scalarModel.whetherDisabled();
         final boolean mustBeEditable = scalarModel.mustBeEditable();
         if (disableReasonIfAny != null) {
@@ -286,7 +288,7 @@ implements ScalarModelSubscriber {
         } else {
             if (scalarModel.isViewMode()) {
                 onInitializeNotEditable();
-            } else {        
+            } else {
                 onInitializeEditable();
             }
         }
@@ -344,13 +346,15 @@ implements ScalarModelSubscriber {
 
         // find associated actions for this scalar property (only properties will have any.)
         final ScalarModel.AssociatedActions associatedActions =
-                scalarModel.getAssociatedActions(); 
+                scalarModel.getAssociatedActions();
         final ObjectAction inlineActionIfAny =
                 associatedActions.getFirstAssociatedWithInlineAsIfEdit();
-        final List<ObjectAction> remainingAssociated = associatedActions.getRemainingAssociated();
+        val remainingAssociated = associatedActions.getRemainingAssociated();
 
         // convert those actions into UI layer widgets
-        final List<LinkAndLabel> linkAndLabels  = LinkAndLabelUtil.asActionLinks(this.scalarModel, remainingAssociated);
+        final Can<LinkAndLabel> linkAndLabels  = LinkAndLabelUtil
+                .asActionLinks(this.scalarModel, remainingAssociated.stream())
+                .collect(Can.toCan());
 
         final InlinePromptConfig inlinePromptConfig = getInlinePromptConfig();
         if(inlinePromptConfig.isSupported()) {
@@ -369,38 +373,45 @@ implements ScalarModelSubscriber {
 
             // start off assuming that neither the property nor any of the associated actions
             // are using inline prompts
-            Component componentToHideIfAny = inlinePromptLink;
+
+            val componentToHideRef = _Refs.<Component>objectRef(inlinePromptLink);
+            //Component componentToHideIfAny = inlinePromptLink;
 
             if (this.scalarModel.getPromptStyle().isInline() && scalarModel.canEnterEditMode()) {
                 // we configure the prompt link if _this_ property is configured for inline edits...
                 configureInlinePromptLinkCallback(inlinePromptLink);
-                componentToHideIfAny = inlinePromptConfig.getComponentToHideIfAny();
+                componentToHideRef.setValue(inlinePromptConfig.getComponentToHideIfAny());
 
             } else {
 
                 // not editable property, but maybe one of the actions is.
                 if(inlineActionIfAny != null) {
 
-                    final LinkAndLabel linkAndLabelAsIfEdit = LinkAndLabelUtil.asActionLink(this.scalarModel, inlineActionIfAny);
-                    final ActionLink actionLinkInlineAsIfEdit = (ActionLink) linkAndLabelAsIfEdit.getUiComponent();
+                    LinkAndLabelUtil.asActionLink(this.scalarModel, inlineActionIfAny)
+                    .findFirst()
+                    .map(LinkAndLabel::getUiComponent)
+                    .map(ActionLink.class::cast)
+                    .ifPresent(actionLinkInlineAsIfEdit->{
+
+                        if(actionLinkInlineAsIfEdit.isVisible() && actionLinkInlineAsIfEdit.isEnabled()) {
+                            configureInlinePromptLinkCallback(inlinePromptLink, actionLinkInlineAsIfEdit);
+                            componentToHideRef.setValue(inlinePromptConfig.getComponentToHideIfAny());
+                        }
+
+                    });
 
-                    if(actionLinkInlineAsIfEdit.isVisible() && actionLinkInlineAsIfEdit.isEnabled()) {
-                        configureInlinePromptLinkCallback(inlinePromptLink, actionLinkInlineAsIfEdit);
-                        componentToHideIfAny = inlinePromptConfig.getComponentToHideIfAny();
-                    }
                 }
             }
 
+            componentToHideRef.getValue()
+            .ifPresent(componentToHide->componentToHide.setVisibilityAllowed(false));
 
-            if(componentToHideIfAny != null) {
-                componentToHideIfAny.setVisibilityAllowed(false);
-            }
         }
 
         // prevent from tabbing into non-editable widgets.
-        if(scalarModel.isProperty() 
+        if(scalarModel.isProperty()
                 && scalarModel.getMode() == EntityModel.Mode.VIEW
-                && (scalarModel.getPromptStyle().isDialog() 
+                && (scalarModel.getPromptStyle().isDialog()
                         || !scalarModel.canEnterEditMode())) {
             getScalarValueComponent().add(new AttributeAppender("tabindex", "-1"));
         }
@@ -508,11 +519,11 @@ implements ScalarModelSubscriber {
 
         @Override
         protected void onUpdate(AjaxRequestTarget target) {
-            
+
             _Probe.entryPoint(EntryPoint.USER_INTERACTION, "Wicket Ajax Request, "
                     + "originating from User either having changed a Property value during inline editing "
                     + "or having changed a Parameter value within an open ActionPrompt.");
-            
+
             for (ScalarModelSubscriber subscriber : scalarPanel.subscribers) {
                 subscriber.onUpdate(target, scalarPanel);
             }
@@ -732,7 +743,7 @@ implements ScalarModelSubscriber {
 
             @Override
             protected void onEvent(final AjaxRequestTarget target) {
-                
+
                 _Probe.entryPoint(EntryPoint.USER_INTERACTION, "Wicket Ajax Request, "
                         + "originating from User clicking on an editable Property to start inline editing.");
 
@@ -858,11 +869,14 @@ implements ScalarModelSubscriber {
 
     private void addActionLinksBelowAndRight(
             final MarkupContainer labelIfRegular,
-            final List<LinkAndLabel> linkAndLabels) {
-        final List<LinkAndLabel> linksBelow = LinkAndLabel.positioned(linkAndLabels, ActionLayout.Position.BELOW);
+            final Can<LinkAndLabel> linkAndLabels) {
+
+        val linksBelow = linkAndLabels
+                .filter(LinkAndLabel.positioned(ActionLayout.Position.BELOW));
         AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ASSOCIATED_ACTION_LINKS_BELOW, linksBelow, AdditionalLinksPanel.Style.INLINE_LIST);
 
-        final List<LinkAndLabel> linksRight = LinkAndLabel.positioned(linkAndLabels, ActionLayout.Position.RIGHT);
+        val linksRight = linkAndLabels
+                .filter(LinkAndLabel.positioned(ActionLayout.Position.RIGHT));
         AdditionalLinksPanel.addAdditionalLinks(labelIfRegular, ID_ASSOCIATED_ACTION_LINKS_RIGHT, linksRight, AdditionalLinksPanel.Style.DROPDOWN);
     }
 
@@ -876,7 +890,7 @@ implements ScalarModelSubscriber {
      */
     private void addPositioningCssTo(
             final MarkupContainer markupContainer,
-            final List<LinkAndLabel> actionLinks) {
+            final Can<LinkAndLabel> actionLinks) {
         CssClassAppender.appendCssClassTo(markupContainer, determinePropParamLayoutCss(getModel()));
         CssClassAppender.appendCssClassTo(markupContainer, determineActionLayoutPositioningCss(actionLinks));
     }
@@ -902,12 +916,12 @@ implements ScalarModelSubscriber {
         return "label-left";
     }
 
-    private static String determineActionLayoutPositioningCss(List<LinkAndLabel> entityActionLinks) {
+    private static String determineActionLayoutPositioningCss(Can<LinkAndLabel> entityActionLinks) {
         boolean actionsPositionedOnRight = hasActionsPositionedOn(entityActionLinks, ActionLayout.Position.RIGHT);
         return actionsPositionedOnRight ? "actions-right" : null;
     }
 
-    private static boolean hasActionsPositionedOn(final List<LinkAndLabel> entityActionLinks, final ActionLayout.Position position) {
+    private static boolean hasActionsPositionedOn(final Can<LinkAndLabel> entityActionLinks, final ActionLayout.Position position) {
         for (LinkAndLabel entityActionLink : entityActionLinks) {
             if(entityActionLink.getActionUiMetaModel().getPosition() == position) {
                 return true;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanel.java
index 2dbe942..8be7752 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanel.java
@@ -30,6 +30,7 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.wicket.model.models.ActionModel;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelStandalone;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistry;
@@ -41,7 +42,7 @@ import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 import org.apache.isis.viewer.wicket.ui.util.Components;
 import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
-public class StandaloneCollectionPanel 
+public class StandaloneCollectionPanel
 extends PanelAbstract<List<ManagedObject>, EntityCollectionModel>
 implements CollectionCountProvider, CollectionSelectorProvider {
 
@@ -57,24 +58,24 @@ implements CollectionCountProvider, CollectionSelectorProvider {
 
     private MarkupContainer outerDiv = this;
 
-    public StandaloneCollectionPanel(final String id, final EntityCollectionModel entityCollectionModel) {
-        super(id, entityCollectionModel);
+    public StandaloneCollectionPanel(final String id, final EntityCollectionModelStandalone collectionModel) {
+        super(id, collectionModel);
 
         outerDiv = new WebMarkupContainer(ID_STANDALONE_COLLECTION);
 
         addOrReplace(outerDiv);
 
-        ActionModel actionModel = entityCollectionModel.getActionModelHint();
+        ActionModel actionModel = collectionModel.getActionModel();
         ObjectAction action = actionModel.getMetaModel();
         outerDiv.addOrReplace(new Label(StandaloneCollectionPanel.ID_ACTION_NAME, Model.of(action.getName())));
 
         CssClassAppender.appendCssClassTo(outerDiv,
                 CssClassAppender.asCssStyle("isis-" + action.getOnType().getLogicalTypeName().replace('.', '-') + "-" + action.getId()));
         CssClassAppender.appendCssClassTo(outerDiv,
-                CssClassAppender.asCssStyle("isis-" + entityCollectionModel.getTypeOfSpecification().getLogicalTypeName().replace('.','-')));
+                CssClassAppender.asCssStyle("isis-" + collectionModel.getTypeOfSpecification().getLogicalTypeName().replace('.','-')));
 
         // selector
-        final CollectionSelectorHelper selectorHelper = new CollectionSelectorHelper(entityCollectionModel, getComponentFactoryRegistry());
+        final CollectionSelectorHelper selectorHelper = new CollectionSelectorHelper(collectionModel, getComponentFactoryRegistry());
 
         final List<ComponentFactory> componentFactories = selectorHelper.getComponentFactories();
 
@@ -82,7 +83,7 @@ implements CollectionCountProvider, CollectionSelectorProvider {
             Components.permanentlyHide(outerDiv, ID_SELECTOR_DROPDOWN);
             this.selectorDropdownPanel = null;
         } else {
-            CollectionSelectorPanel selectorDropdownPanel = new CollectionSelectorPanel(ID_SELECTOR_DROPDOWN, entityCollectionModel);
+            CollectionSelectorPanel selectorDropdownPanel = new CollectionSelectorPanel(ID_SELECTOR_DROPDOWN, collectionModel);
 
             final Model<ComponentFactory> componentFactoryModel = new Model<>();
 
@@ -98,7 +99,7 @@ implements CollectionCountProvider, CollectionSelectorProvider {
         }
 
         final ComponentFactoryRegistry componentFactoryRegistry = getComponentFactoryRegistry();
-        componentFactoryRegistry.addOrReplaceComponent(outerDiv, ComponentType.COLLECTION_CONTENTS, entityCollectionModel);
+        componentFactoryRegistry.addOrReplaceComponent(outerDiv, ComponentType.COLLECTION_CONTENTS, collectionModel);
     }
 
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanelFactory.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanelFactory.java
index 080f6e4..5c5bd29 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanelFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/standalonecollection/StandaloneCollectionPanelFactory.java
@@ -22,11 +22,13 @@ package org.apache.isis.viewer.wicket.ui.components.standalonecollection;
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelStandalone;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 
+import lombok.val;
+
 /**
  * {@link ComponentFactory} for {@link StandaloneCollectionPanel}.
  */
@@ -40,13 +42,13 @@ public class StandaloneCollectionPanelFactory extends ComponentFactoryAbstract {
 
     @Override
     public ApplicationAdvice appliesTo(final IModel<?> model) {
-        return appliesIf(model instanceof EntityCollectionModel);
+        return appliesIf(model instanceof EntityCollectionModelStandalone);
     }
 
     @Override
     public Component createComponent(final String id, final IModel<?> model) {
-        final EntityCollectionModel actionModel = (EntityCollectionModel) model;
-        return new StandaloneCollectionPanel(id, actionModel);
+        val collectionModel = (EntityCollectionModelStandalone) model;
+        return new StandaloneCollectionPanel(id, collectionModel);
     }
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java
index b6c027e..01a8406 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java
@@ -23,8 +23,7 @@ import org.apache.wicket.Component;
 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
 
 import org.apache.isis.viewer.wicket.model.common.PageParametersUtils;
-import org.apache.isis.viewer.wicket.model.models.ActionModel;
-import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityCollectionModelStandalone;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 
@@ -39,18 +38,13 @@ public class StandaloneCollectionPage extends PageAbstract {
     /**
      * For use with {@link Component#setResponsePage(org.apache.wicket.request.component.IRequestablePage)}
      */
-    public StandaloneCollectionPage(final EntityCollectionModel model) {
-        super(PageParametersUtils.newPageParameters(), actionNameFrom(model), ComponentType.STANDALONE_COLLECTION);
-        addChildComponents(themeDiv, model);
+    public StandaloneCollectionPage(final EntityCollectionModelStandalone collectionModel) {
+        super(PageParametersUtils.newPageParameters(),
+                collectionModel.getActionModel().getMetaModel().getName(),
+                ComponentType.STANDALONE_COLLECTION);
 
+        addChildComponents(themeDiv, collectionModel);
         addBookmarkedPages(themeDiv);
     }
 
-    private static String actionNameFrom(final EntityCollectionModel model) {
-        ActionModel actionModel = model.getActionModelHint();
-        if(actionModel != null) {
-            return actionModel.getMetaModel().getName();
-        }
-        return "Results"; // fallback, probably not required because hint should always exist on the model.
-    }
 }