diff --git a/src/Entity/WorkspacePointer.php b/src/Entity/WorkspacePointer.php
new file mode 100644
index 0000000..be50f30
--- /dev/null
+++ b/src/Entity/WorkspacePointer.php
@@ -0,0 +1,140 @@
+<?php
+
+namespace Drupal\workspace\Entity;
+
+use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityChangedTrait;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\multiversion\Entity\WorkspaceInterface;
+use Drupal\workspace\WorkspacePointerInterface;
+
+/**
+ * Defines the Workspace pointer entity.
+ *
+ * @ingroup workspace
+ *
+ * @ContentEntityType(
+ *   id = "workspace_pointer",
+ *   label = @Translation("Workspace pointer"),
+ *   base_table = "workspace_pointer",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "name",
+ *     "uuid" = "uuid",
+ *   },
+ * )
+ */
+class WorkspacePointer extends ContentEntityBase implements WorkspacePointerInterface {
+  use EntityChangedTrait;
+  /**
+   * {@inheritdoc}
+   */
+  public static function preCreate(EntityStorageInterface $storage_controller, array &$values) {
+    parent::preCreate($storage_controller, $values);
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getName() {
+    return $this->get('name')->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setName($name) {
+    $this->set('name', $name);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getCreatedTime() {
+    return $this->get('created')->value;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setCreatedTime($timestamp) {
+    $this->set('created', $timestamp);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setWorkspace(WorkspaceInterface $workspace) {
+    $this->set('workspace', $workspace->id());
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setWorkspaceId($workspace_id) {
+    $this->set('workspace', $workspace_id);
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getWorkspace() {
+    $ws = $this->get('workspace')->entity;
+    return $ws;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getWorkspaceId() {
+    return $this->get('workspace')->target_id;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+    $fields['id'] = BaseFieldDefinition::create('integer')
+      ->setLabel(t('ID'))
+      ->setDescription(t('The ID of the Workspace pointer entity.'))
+      ->setReadOnly(TRUE);
+    $fields['uuid'] = BaseFieldDefinition::create('uuid')
+      ->setLabel(t('UUID'))
+      ->setDescription(t('The UUID of the Workspace pointer entity.'))
+      ->setReadOnly(TRUE);
+
+    $fields['name'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Name'))
+      ->setDescription(t('The name of the Workspace pointer entity.'))
+      ->setSettings(array(
+        'max_length' => 50,
+        'text_processing' => 0,
+      ))
+      ->setDefaultValue('')
+      ->setDisplayConfigurable('form', FALSE)
+      ->setDisplayConfigurable('view', FALSE);
+
+    $fields['created'] = BaseFieldDefinition::create('created')
+      ->setLabel(t('Created'))
+      ->setDescription(t('The time that the entity was created.'));
+
+    $fields['changed'] = BaseFieldDefinition::create('changed')
+      ->setLabel(t('Changed'))
+      ->setDescription(t('The time that the entity was last edited.'));
+
+    $fields['workspace'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('Workspace'))
+      ->setDescription(t('A reference to the workspace'))
+      ->setSetting('target_type', 'workspace');
+
+    return $fields;
+  }
+
+}
diff --git a/src/Entity/WorkspacePointerViewsData.php b/src/Entity/WorkspacePointerViewsData.php
new file mode 100644
index 0000000..5f8438f
--- /dev/null
+++ b/src/Entity/WorkspacePointerViewsData.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\workspace\Entity\WorkspacePointer.
+ */
+
+namespace Drupal\workspace\Entity;
+
+use Drupal\views\EntityViewsData;
+use Drupal\views\EntityViewsDataInterface;
+
+/**
+ * Provides Views data for Workspace pointer entities.
+ */
+class WorkspacePointerViewsData extends EntityViewsData implements EntityViewsDataInterface {
+  /**
+   * {@inheritdoc}
+   */
+  public function getViewsData() {
+    $data = parent::getViewsData();
+
+    $data['workspace_pointer']['table']['base'] = array(
+      'field' => 'id',
+      'title' => $this->t('Workspace pointer'),
+      'help' => $this->t('The Workspace pointer ID.'),
+    );
+
+    return $data;
+  }
+
+}
diff --git a/src/EntityOperations.php b/src/EntityOperations.php
new file mode 100644
index 0000000..158317a
--- /dev/null
+++ b/src/EntityOperations.php
@@ -0,0 +1,56 @@
+<?php
+
+namespace Drupal\workspace;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\multiversion\Entity\WorkspaceInterface;
+use Drupal\multiversion\MultiversionManagerInterface;
+
+/**
+ * Defines a class for reacting to entity events.
+ */
+class EntityOperations {
+
+  /**
+   * @var \Drupal\multiversion\MultiversionManagerInterface
+   */
+  protected $multiversionManager;
+
+  /**
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * Constructs a new Toolbar.
+   *
+   * @param \Drupal\multiversion\MultiversionManagerInterface $multiversion_manager
+   */
+  public function __construct(MultiversionManagerInterface $multiversion_manager, EntityTypeManagerInterface $entity_type_manager) {
+    $this->multiversionManager = $multiversion_manager;
+    $this->entityTypeManager = $entity_type_manager;
+  }
+
+  /**
+   * Hook bridge for hook_workspace_insert()
+   *
+   * @see hook_ENTITY_TYPE_insert()
+   *
+   * @param \Drupal\multiversion\Entity\WorkspaceInterface $workspace
+   *   The workspace entity that is being created.
+   */
+  public function workspaceInsert(WorkspaceInterface $workspace) {
+    // Create a new pointer to every Workspace that gets created.
+    // This is mainly so that we can always backtrack from a Workspace to a
+    // pointer to provide a consistent API to replicators.
+
+    /** @var WorkspacePointerInterface $pointer */
+    $pointer = $this->entityTypeManager->getStorage('workspace_pointer')->create();
+
+    $pointer->setWorkspace($workspace);
+    $pointer->setName('Pointer to ' . $workspace->label());
+
+    $pointer->save();
+  }
+
+}
diff --git a/src/EntityTypeAlter.php b/src/EntityTypeAlter.php
deleted file mode 100644
index 06b7ad9..0000000
--- a/src/EntityTypeAlter.php
+++ /dev/null
@@ -1,87 +0,0 @@
-<?php
-
-namespace Drupal\workspace;
-
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\multiversion\MultiversionManagerInterface;
-
-class EntityTypeAlter {
-
-  /**
-   * @var \Drupal\multiversion\MultiversionManagerInterface
-   */
-  protected $multiversionManager;
-
-  /**
-   * Constructs a new Toolbar.
-   *
-   * @param \Drupal\multiversion\MultiversionManagerInterface $multiversion_manager
-   */
-  public function __construct(MultiversionManagerInterface $multiversion_manager) {
-    $this->multiversionManager = $multiversion_manager;
-  }
-
-  /**
-   * @param array $entity_types
-   */
-  public function entityTypeAlter(array &$entity_types) {
-    if (isset($entity_types['workspace_type'])) {
-      $this->alterWorkspaceType($entity_types['workspace_type']);
-    }
-
-    if (isset($entity_types['workspace'])) {
-      $this->alterWorkspace($entity_types['workspace']);
-    }
-
-    foreach ($entity_types as $entity_type) {
-      $this->addRevisionLinks($entity_type);
-    }
-  }
-
-  /**
-   * @param \Drupal\Core\Entity\EntityTypeInterface $workspace_type
-   */
-  protected function alterWorkspaceType(EntityTypeInterface &$workspace_type) {
-    $workspace_type->setHandlerClass('list_builder', 'Drupal\workspace\WorkspaceTypeListBuilder');
-    $workspace_type->setHandlerClass('route_provider', ['html' => 'Drupal\Core\Entity\Routing\AdminHtmlRouteProvider']);
-    $workspace_type->setHandlerClass('form', [
-      'default' => 'Drupal\workspace\Entity\Form\WorkspaceTypeForm',
-      'add' => 'Drupal\workspace\Entity\Form\WorkspaceTypeForm',
-      'edit' => 'Drupal\workspace\Entity\Form\WorkspaceTypeForm',
-      'delete' => 'Drupal\workspace\Entity\Form\WorkspaceTypeDeleteForm'
-    ]);
-    $workspace_type->setLinkTemplate('edit-form', '/admin/structure/workspace/types/{workspace_type}/edit');
-    $workspace_type->setLinkTemplate('delete-form', '/admin/structure/workspace/types/{workspace_type}/delete');
-    $workspace_type->setLinkTemplate('collection', '/admin/structure/workspace/types');
-  }
-
-  /**
-   * @param \Drupal\Core\Entity\EntityTypeInterface $workspace
-   */
-  protected function alterWorkspace(EntityTypeInterface &$workspace) {
-    $workspace ->setHandlerClass('list_builder', 'Drupal\workspace\WorkspaceListBuilder');
-    $workspace->setHandlerClass('route_provider', ['html' => 'Drupal\Core\Entity\Routing\AdminHtmlRouteProvider']);
-    $workspace->setHandlerClass('form', [
-      'default' => 'Drupal\workspace\Entity\Form\WorkspaceForm',
-      'add' => 'Drupal\workspace\Entity\Form\WorkspaceForm',
-      'edit' => 'Drupal\workspace\Entity\Form\WorkspaceForm',
-    ]);
-    $workspace->setLinkTemplate('collection', '/admin/structure/workspace');
-    $workspace->setLinkTemplate('edit-form', '/admin/structure/workspace/{workspace}/edit');
-    $workspace->setLinkTemplate('activate-form', '/admin/structure/workspace/{workspace}/activate');
-    $workspace->set('field_ui_base_route', 'entity.workspace_type.edit_form');
-  }
-
-  /**
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   */
-  protected function addRevisionLinks(EntityTypeInterface &$entity_type) {
-    if ($this->multiversionManager->isEnabledEntityType($entity_type)) {
-      if ($entity_type->hasViewBuilderClass() && $entity_type->hasLinkTemplate('canonical')) {
-        $entity_type->setLinkTemplate('version-tree', $entity_type->getLinkTemplate('canonical') . '/tree');
-        $entity_type->setLinkTemplate('version-history', $entity_type->getLinkTemplate('canonical') . '/revisions');
-        $entity_type->setLinkTemplate('revision', $entity_type->getLinkTemplate('canonical') . '/revisions/{' . $entity_type->id() . '_revision}/view');
-      }
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/EntityTypeInfo.php b/src/EntityTypeInfo.php
new file mode 100644
index 0000000..b162163
--- /dev/null
+++ b/src/EntityTypeInfo.php
@@ -0,0 +1,169 @@
+<?php
+
+namespace Drupal\workspace;
+
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\multiversion\MultiversionManagerInterface;
+use Drupal\workspace\Entity\Form\WorkspaceForm;
+use Drupal\workspace\Entity\Form\WorkspaceTypeDeleteForm;
+use Drupal\workspace\Entity\Form\WorkspaceTypeForm;
+
+/**
+ * Service class for manipulating entity type information.
+ *
+ * This class contains primarily bridged hooks for compile-time or
+ * cache-clear-time hooks. Runtime hooks should be placed in EntityOperations.
+ */
+class EntityTypeInfo {
+
+  /**
+   * @var \Drupal\multiversion\MultiversionManagerInterface
+   */
+  protected $multiversionManager;
+
+  /**
+   * Constructs a new Toolbar.
+   *
+   * @param \Drupal\multiversion\MultiversionManagerInterface $multiversion_manager
+   */
+  public function __construct(MultiversionManagerInterface $multiversion_manager) {
+    $this->multiversionManager = $multiversion_manager;
+  }
+
+  /**
+   * @param array $entity_types
+   */
+  public function entityTypeAlter(array &$entity_types) {
+    if (isset($entity_types['workspace_type'])) {
+      $entity_types['workspace_type'] = $this->alterWorkspaceType($entity_types['workspace_type']);
+    }
+
+    if (isset($entity_types['workspace'])) {
+      $entity_types['workspace'] = $this->alterWorkspace($entity_types['workspace']);
+    }
+
+    foreach ($this->selectMultiversionedUiEntityTypes($entity_types) as $type_name => $entity_type) {
+      $entity_types[$type_name] = $this->addRevisionLinks($entity_type);
+    }
+  }
+
+  /**
+   * Returns just those entity definitions that need multiversion UI enhancement.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
+   *   The entity types to check.
+   * @return EntityTypeInterface[]
+   *   Just the entities that we care about.
+   */
+  protected function selectMultiversionedUiEntityTypes(array $entity_types) {
+    return array_filter($entity_types, function (EntityTypeInterface $type) use ($entity_types) {
+      $this->multiversionManager->isEnabledEntityType($type)
+      && $type->hasViewBuilderClass()
+      && $type->hasLinkTemplate('canonical');
+    });
+  }
+
+  /**
+   * @param \Drupal\Core\Entity\EntityTypeInterface $workspace_type
+   *
+   * @return \Drupal\Core\Entity\EntityTypeInterface
+   */
+  protected function alterWorkspaceType(EntityTypeInterface $workspace_type) {
+    $workspace_type->setHandlerClass('list_builder', WorkspaceTypeListBuilder::class);
+    $workspace_type->setHandlerClass('route_provider', ['html' => AdminHtmlRouteProvider::class]);
+    $workspace_type->setHandlerClass('form', [
+      'default' => WorkspaceTypeForm::class,
+      'add' => WorkspaceTypeForm::class,
+      'edit' => WorkspaceTypeForm::class,
+      'delete' => WorkspaceTypeDeleteForm::class,
+    ]);
+
+    $workspace_type->setLinkTemplate('edit-form', '/admin/structure/workspace/types/{workspace_type}/edit');
+    $workspace_type->setLinkTemplate('delete-form', '/admin/structure/workspace/types/{workspace_type}/delete');
+    $workspace_type->setLinkTemplate('collection', '/admin/structure/workspace/types');
+
+    return $workspace_type;
+  }
+
+  /**
+   * @param \Drupal\Core\Entity\EntityTypeInterface $workspace
+   *
+   * @return \Drupal\Core\Entity\EntityTypeInterface
+   */
+  protected function alterWorkspace(EntityTypeInterface $workspace) {
+    $workspace ->setHandlerClass('list_builder', WorkspaceListBuilder::class);
+    $workspace->setHandlerClass('route_provider', ['html' => AdminHtmlRouteProvider::class]);
+    $workspace->setHandlerClass('form', [
+      'default' => WorkspaceForm::class,
+      'add' => WorkspaceForm::class,
+      'edit' => WorkspaceForm::class,
+    ]);
+
+    $workspace->setLinkTemplate('collection', '/admin/structure/workspace');
+    $workspace->setLinkTemplate('edit-form', '/admin/structure/workspace/{workspace}/edit');
+    $workspace->setLinkTemplate('activate-form', '/admin/structure/workspace/{workspace}/activate');
+    $workspace->set('field_ui_base_route', 'entity.workspace_type.edit_form');
+
+    return $workspace;
+  }
+
+  /**
+   * Adds additional link relationships to an entity.
+   *
+   * If these links already exist they will not be overridden.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   An entity type defintion to which to add links.
+   *
+   * @return \Drupal\Core\Entity\EntityTypeInterface
+   *   The modified type definition.
+   */
+  protected function addRevisionLinks(EntityTypeInterface $entity_type) {
+
+    if (!$entity_type->hasLinkTemplate('version-tree')) {
+      $entity_type->setLinkTemplate('version-tree', $entity_type->getLinkTemplate('canonical') . '/tree');
+    }
+
+    if (!$entity_type->hasLinkTemplate('version-history')) {
+      $entity_type->setLinkTemplate('version-history', $entity_type->getLinkTemplate('canonical') . '/revisions');
+    }
+
+    if (!$entity_type->hasLinkTemplate('revision')) {
+      $entity_type->setLinkTemplate('revision', $entity_type->getLinkTemplate('canonical') . '/revisions/{' . $entity_type->id() . '_revision}/view');
+    }
+
+    return $entity_type;
+  }
+
+  /**
+   * Adds base field info to an entity type.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
+   *   Entity type for adding base fields to.
+   *
+   * @return \Drupal\Core\Field\BaseFieldDefinition[]
+   *   New fields added by moderation state.
+   */
+  public function entityBaseFieldInfo(EntityTypeInterface $entity_type) {
+    if ($entity_type->id() != 'workspace') {
+      return [];
+    }
+
+    $fields['upstream'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('Assign default target workspace'))
+      ->setDescription(t('The workspace to push to and pull from.'))
+      ->setRevisionable(TRUE)
+      ->setRequired(TRUE)
+      ->setSetting('target_type', 'workspace_pointer')
+      ->setDefaultValueCallback('workspace_active_id')
+      ->setDisplayOptions('form', [
+        'type' => 'options_buttons',
+        'weight' => 0
+      ])
+      ->setDisplayConfigurable('form', TRUE);
+
+    return $fields;
+  }
+}
diff --git a/src/EventSubscriber/WorkbenchModerationSubscriber.php b/src/EventSubscriber/WorkbenchModerationSubscriber.php
index ccb5015..d641646 100644
--- a/src/EventSubscriber/WorkbenchModerationSubscriber.php
+++ b/src/EventSubscriber/WorkbenchModerationSubscriber.php
@@ -7,7 +7,6 @@ use Drupal\multiversion\Entity\WorkspaceInterface;
 use Drupal\workbench_moderation\Entity\ModerationState;
 use Drupal\workbench_moderation\Event\WorkbenchModerationEvents;
 use Drupal\workbench_moderation\Event\WorkbenchModerationTransitionEvent;
-use Drupal\workspace\PointerInterface;
 use Drupal\workspace\ReplicatorManager;
 use Drupal\workspace\WorkspacePointerInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -23,18 +22,12 @@ class WorkbenchModerationSubscriber implements EventSubscriberInterface {
   protected $entityTypeManager;
 
   /**
-   * @var \Drupal\workspace\WorkspacePointerInterface
-   */
-  protected $workspacePointer;
-
-  /**
    * @var \Drupal\workspace\ReplicatorManager
    */
   protected $replicatorManager;
 
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, WorkspacePointerInterface $workspace_pointer, ReplicatorManager $replicator_manager) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, ReplicatorManager $replicator_manager) {
     $this->entityTypeManager = $entity_type_manager;
-    $this->workspacePointer = $workspace_pointer;
     $this->replicatorManager = $replicator_manager;
   }
 
@@ -79,19 +72,36 @@ class WorkbenchModerationSubscriber implements EventSubscriberInterface {
    */
   protected function mergeWorkspaceToParent(WorkspaceInterface $workspace) {
     // This may be insufficient for handling a missing parent.
-    /** @var WorkspaceInterface $parent_workspace */
-    $parent_workspace = $workspace->get('upstream')->entity;
-    if (!$parent_workspace) {
+    /** @var WorkspacePointerInterface $parent_workspace */
+    $parent_workspace_pointer = $workspace->get('upstream')->entity;
+    if (!$parent_workspace_pointer) {
       // @todo Should we silently ignore this, or throw an error, or...?
       return;
     }
 
-    /** @var PointerInterface $source_pointer */
-    $source_pointer = $this->workspacePointer->get('workspace:' . $workspace->id());
-    /** @var PointerInterface $target_pointer */
-    $target_pointer = $this->workspacePointer->get('workspace:' . $parent_workspace->id());
+    $source_pointer = $this->getPointerToWorkspace($workspace);
+
+    $this->replicatorManager->replicate($source_pointer, $parent_workspace_pointer);
+  }
 
-    $this->replicatorManager->replicate($source_pointer, $target_pointer);
+  /**
+   * Returns a pointer to the specified workspace.
+   *
+   * In most cases this pointer will be unique, but that is not guaranteed
+   * by the schema. If there are multiple pointers, which one is returned is
+   * undefined.
+   *
+   * @param \Drupal\multiversion\Entity\WorkspaceInterface $workspace
+   *   The workspace for which we want a pointer.
+   * @return WorkspacePointerInterface
+   *   The pointer to the provided workspace.
+   */
+  protected function getPointerToWorkspace(WorkspaceInterface $workspace) {
+    $pointers = $this->entityTypeManager
+      ->getStorage('pointer')
+      ->loadByProperties(['workspace' => $workspace->id()]);
+    $pointer = reset($pointers);
+    return $pointer;
   }
 
   /**
diff --git a/src/InternalReplicator.php b/src/InternalReplicator.php
index dda2d3c..aebb99f 100644
--- a/src/InternalReplicator.php
+++ b/src/InternalReplicator.php
@@ -34,25 +34,22 @@ class InternalReplicator implements ReplicatorInterface {
   /**
    * {@inheritdoc}
    */
-  public function applies(PointerInterface $source, PointerInterface $target) {
-    if (isset($source->data()['workspace']) && isset($target->data()['workspace'])) {
-      $source_workspace = Workspace::load($source->data()['workspace']);
-      $target_workspace = Workspace::load($target->data()['workspace']);
-      if (($source_workspace instanceof WorkspaceInterface) && ($target_workspace instanceof WorkspaceInterface)) {
-        return TRUE;
-      }
-    }
-    return FALSE;
+  public function applies(WorkspacePointerInterface $source, WorkspacePointerInterface $target) {
+    $source_workspace = $source->getWorkspace();
+    $target_workspace = $target->getWorkspace();
+
+    return ($source_workspace instanceof WorkspaceInterface) && ($target_workspace instanceof WorkspaceInterface);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function replicate(PointerInterface $source, PointerInterface $target) {
+  public function replicate(WorkspacePointerInterface $source, WorkspacePointerInterface $target) {
     // Set active workspace to source.
-    $source_workspace = Workspace::load($source->data()['workspace']);
-    $target_workspace = Workspace::load($target->data()['workspace']);
+    $source_workspace = $source->getWorkspace();
+    $target_workspace = $target->getWorkspace();
     $this->workspaceManager->setActiveWorkspace($source_workspace);
+
     // Get multiversion supported content entities.
     $entity_types = $this->multiversionManager->getSupportedEntityTypes();
     // Load all entities.
@@ -66,4 +63,4 @@ class InternalReplicator implements ReplicatorInterface {
     }
   }
 
-}
\ No newline at end of file
+}
diff --git a/src/Plugin/RulesAction/ReplicateContent.php b/src/Plugin/RulesAction/ReplicateContent.php
index 37e60c8..3d5f88c 100644
--- a/src/Plugin/RulesAction/ReplicateContent.php
+++ b/src/Plugin/RulesAction/ReplicateContent.php
@@ -8,12 +8,13 @@
 namespace Drupal\workspace\Plugin\RulesAction;
 
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\multiversion\Entity\Workspace;
+use Drupal\multiversion\Entity\WorkspaceInterface;
 use Drupal\multiversion\MultiversionManagerInterface;
 use Drupal\multiversion\Workspace\WorkspaceManagerInterface;
 use Drupal\rules\Core\RulesActionBase;
-use Drupal\workspace\Pointer;
 use Drupal\workspace\ReplicatorManager;
 use Drupal\workspace\WorkspacePointerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -34,13 +35,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
  * )
  *
  */
-class ReplicateContent extends RulesActionBase implements ContainerFactoryPluginInterface{
+class ReplicateContent extends RulesActionBase implements ContainerFactoryPluginInterface {
 
   /** @var  WorkspaceManagerInterface */
   protected $workspaceManager;
 
-  /** @var  WorkspacePointerInterface */
-  protected $workspacePointer;
+  /** @var  EntityTypeManagerInterface */
+  protected $entityTypeManager;
 
   /** @var  ReplicatorManager */
   protected $replicatorManager;
@@ -49,7 +50,7 @@ class ReplicateContent extends RulesActionBase implements ContainerFactoryPlugin
   protected $multiversionManager;
 
   /**
-   * Constructs an ReplicateContent object.
+   * Constructs a new ReplicateContent.
    *
    * @param array $configuration
    *   A configuration array containing information about the plugin instance.
@@ -58,13 +59,14 @@ class ReplicateContent extends RulesActionBase implements ContainerFactoryPlugin
    * @param mixed $plugin_definition
    *   The plugin implementation definition.
    * @param \Drupal\multiversion\Workspace\WorkspaceManagerInterface $workspace_manager
-   * @param \Drupal\workspace\WorkspacePointerInterface $workspace_pointer
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
    * @param \Drupal\workspace\ReplicatorManager $replicator_manager
+   * @param \Drupal\multiversion\MultiversionManagerInterface $multiversion_manager
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, WorkspaceManagerInterface $workspace_manager, WorkspacePointerInterface $workspace_pointer, ReplicatorManager $replicator_manager, MultiversionManagerInterface $multiversion_manager) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, WorkspaceManagerInterface $workspace_manager, EntityTypeManagerInterface $entity_type_manager, ReplicatorManager $replicator_manager, MultiversionManagerInterface $multiversion_manager) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->workspaceManager = $workspace_manager;
-    $this->workspacePointer = $workspace_pointer;
+    $this->entityTypeManager = $entity_type_manager;
     $this->replicatorManager = $replicator_manager;
     $this->multiversionManager = $multiversion_manager;
   }
@@ -78,7 +80,7 @@ class ReplicateContent extends RulesActionBase implements ContainerFactoryPlugin
       $plugin_id,
       $plugin_definition,
       $container->get('workspace.manager'),
-      $container->get('workspace.pointer'),
+      $container->get('entity_type.manager'),
       $container->get('workspace.replicator_manager'),
       $container->get('multiversion.manager')
       );
@@ -87,22 +89,18 @@ class ReplicateContent extends RulesActionBase implements ContainerFactoryPlugin
    * Replicate content from active Workspace to it's upstream.
    */
   protected function doExecute(EntityInterface $entity) {
-    $entity_type = $entity->getEntityType();
-    if ($this->multiversionManager->isSupportedEntityType($entity_type)) {
-      /** @var Workspace $workspace */
-      $workspace = $entity->get('workspace')->entity;
-    }
-    else {
-      /** @var Workspace $workspace */
-      $workspace = $this->workspaceManager->getActiveWorkspace();
-    }
-    /** @var Workspace $upstream */
-    $upstream = $workspace->get('upstream')->entity;
-    /** @var Pointer $source */
-    $source = $this->workspacePointer->get('workspace:' . $workspace->id());
-    /** @var Pointer $target */
-    $target = $this->workspacePointer->get('workspace:' . $upstream->id());
+    /** @var Workspace $workspace */
+    $workspace = $this->multiversionManager->isSupportedEntityType($entity->getEntityType())
+      ? $entity->get('workspace')->entity
+      : $this->workspaceManager->getActiveWorkspace();
+
+    $source = $this->getPointerToWorkspace($workspace);
+
+    /** @var WorkspacePointerInterface $upstream */
+    $target = $workspace->get('upstream')->entity;
+
     $result = $this->replicatorManager->replicate($source, $target);
+
     if (!isset($result['error'])) {
       drupal_set_message($this->t('Content replicated from workspace @source to workspace @target',
         ['@source' => $workspace->label(), '@target' => $upstream->label()]));
@@ -112,4 +110,24 @@ class ReplicateContent extends RulesActionBase implements ContainerFactoryPlugin
     }
   }
 
+  /**
+   * Returns a pointer to the specified workspace.
+   *
+   * In most cases this pointer will be unique, but that is not guaranteed
+   * by the schema. If there are multiple pointers, which one is returned is
+   * undefined.
+   *
+   * @param \Drupal\multiversion\Entity\WorkspaceInterface $workspace
+   *   The workspace for which we want a pointer.
+   * @return WorkspacePointerInterface
+   *   The pointer to the provided workspace.
+   */
+  protected function getPointerToWorkspace(WorkspaceInterface $workspace) {
+    $pointers = $this->entityTypeManager
+      ->getStorage('pointer')
+      ->loadByProperties(['workspace' => $workspace->id()]);
+    $pointer = reset($pointers);
+    return $pointer;
+  }
+
 }
diff --git a/src/ReplicatorInterface.php b/src/ReplicatorInterface.php
index 4b7c039..a933e4b 100644
--- a/src/ReplicatorInterface.php
+++ b/src/ReplicatorInterface.php
@@ -13,17 +13,17 @@ namespace Drupal\workspace;
 interface ReplicatorInterface {
 
   /**
-   * @param \Drupal\workspace\PointerInterface $source
-   * @param \Drupal\workspace\PointerInterface $target
+   * @param \Drupal\workspace\WorkspacePointerInterface $source
+   * @param \Drupal\workspace\WorkspacePointerInterface $target
    * @return bool
    */
-  public function applies(PointerInterface $source, PointerInterface $target);
+  public function applies(WorkspacePointerInterface $source, WorkspacePointerInterface $target);
 
   /**
-   * @param \Drupal\workspace\PointerInterface $source
-   * @param \Drupal\workspace\PointerInterface $target
+   * @param \Drupal\workspace\WorkspacePointerInterface $source
+   * @param \Drupal\workspace\WorkspacePointerInterface $target
    * @return array
    */
-  public function replicate(PointerInterface $source, PointerInterface $target);
+  public function replicate(WorkspacePointerInterface $source, WorkspacePointerInterface $target);
 
 }
diff --git a/src/ReplicatorManager.php b/src/ReplicatorManager.php
index c320d35..dbaf8d6 100644
--- a/src/ReplicatorManager.php
+++ b/src/ReplicatorManager.php
@@ -17,7 +17,7 @@ class ReplicatorManager implements ReplicatorInterface {
   /**
    * {@inheritdoc}
    */
-  public function applies(PointerInterface $source, PointerInterface $target) {
+  public function applies(WorkspacePointerInterface $source, WorkspacePointerInterface $target) {
     return TRUE;
   }
 
@@ -33,7 +33,7 @@ class ReplicatorManager implements ReplicatorInterface {
   /**
    * {@inheritdoc}
    */
-  public function replicate(PointerInterface $source, PointerInterface $target) {
+  public function replicate(WorkspacePointerInterface $source, WorkspacePointerInterface $target) {
     /** @var ReplicatorInterface $replicator */
     foreach ($this->replicators as $replicator) {
       if ($replicator->applies($source, $target)) {
diff --git a/src/WorkspacePointer.php b/src/WorkspacePointer.php
deleted file mode 100644
index 42cfa5c..0000000
--- a/src/WorkspacePointer.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-
-namespace Drupal\workspace;
-
-use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
-
-class WorkspacePointer implements WorkspacePointerInterface {
-
-  /**
-   * @var \Drupal\Core\KeyValueStore\KeyValueStoreInterface
-   */
-  protected $keyValueStore;
-
-  /**
-   * @inheritDoc
-   */
-  public function __construct(KeyValueFactoryInterface $key_value_factory) {
-    $this->keyValueStore = $key_value_factory->get('workspace.pointer');
-  }
-
-  /**
-   * @inheritDoc
-   */
-  public function get($key) {
-    return $this->keyValueStore->get($key);
-  }
-
-  /**
-   * @inheritDoc
-   */
-  public function getMultiple(array $keys = []) {
-    if (empty($keys)) {
-      return $this->keyValueStore->getAll();
-    }
-    return $this->keyValueStore->getMultiple($keys);
-  }
-
-  /**
-   * @inheritDoc
-   */
-  public function add(Pointer $pointer) {
-    $this->keyValueStore->set($pointer->id(), $pointer);
-  }
-
-  /**
-   * @inheritDoc
-   */
-  public function addMultiple(array $pointers) {
-    foreach ($pointers as $pointer) {
-      $this->add($pointer);
-    }
-  }
-
-}
\ No newline at end of file
diff --git a/src/WorkspacePointerInterface.php b/src/WorkspacePointerInterface.php
index 9ef7716..fb7c39e 100644
--- a/src/WorkspacePointerInterface.php
+++ b/src/WorkspacePointerInterface.php
@@ -1,32 +1,94 @@
 <?php
 
+
 namespace Drupal\workspace;
 
-interface WorkspacePointerInterface {
+use Drupal\Core\Entity\ContentEntityInterface;
+use Drupal\Core\Entity\EntityChangedInterface;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\multiversion\Entity\WorkspaceInterface;
+use Drupal\user\EntityOwnerInterface;
+
+/**
+ * Provides an interface for defining Workspace pointer entities.
+ *
+ * @ingroup workspace
+ */
+interface WorkspacePointerInterface extends ContentEntityInterface, EntityChangedInterface {
+  // Add get/set methods for your configuration properties here.
+
+  /**
+   * Gets the Workspace pointer name.
+   *
+   * @return string
+   *   Name of the Workspace pointer.
+   */
+  public function getName();
 
   /**
-   * @param string $key
+   * Sets the Workspace pointer name.
    *
-   * @return array
+   * @param string $name
+   *   The Workspace pointer name.
+   *
+   * @return \Drupal\workspace\WorkspacePointerInterface
+   *   The called Workspace pointer entity.
    */
-  public function get($key);
+  public function setName($name);
 
   /**
-   * @param array $keys
+   * Gets the Workspace pointer creation timestamp.
    *
-   * @return array
+   * @return int
+   *   Creation timestamp of the Workspace pointer.
    */
-  public function getMultiple(array $keys);
+  public function getCreatedTime();
 
   /**
-   * @param \Drupal\workspace\Pointer $pointer
-   * @return mixed
+   * Sets the Workspace pointer creation timestamp.
+   *
+   * @param int $timestamp
+   *   The Workspace pointer creation timestamp.
+   *
+   * @return \Drupal\workspace\WorkspacePointerInterface
+   *   The called Workspace pointer entity.
    */
-  public function add(Pointer $pointer);
+  public function setCreatedTime($timestamp);
 
   /**
-   * @param array $pointers
+   * Sets the Workspace this pointer references.
+   *
+   * @param \Drupal\multiversion\Entity\WorkspaceInterface $workspace
+   *
+   * @return $this
+   *   The called Workspace pointer entity.
    */
-  public function addMultiple(array $pointers);
+  public function setWorkspace(WorkspaceInterface $workspace);
 
-}
\ No newline at end of file
+  /**
+   * Returns the referenced workspace entity.
+   *
+   * @return \Drupal\multiversion\Entity\WorkspaceInterface
+   *   The workspace entity.
+   */
+  public function getWorkspace();
+
+  /**
+   * Returns the referenced workspace ID.
+   *
+   * @return int|null
+   *   The workspace ID, or NULL in case the workspace ID field has not been
+   *   set on the entity.
+   */
+  public function getWorkspaceId();
+
+  /**
+   * Sets the referenced workspace ID.
+   *
+   * @param int $workspace_id
+   *   The workspace id.
+   *
+   * @return $this
+   */
+  public function setWorkspaceId($uid);
+}
diff --git a/tests/src/Kernel/WorkspacePointerTest.php b/tests/src/Kernel/WorkspacePointerTest.php
new file mode 100644
index 0000000..a8aa568
--- /dev/null
+++ b/tests/src/Kernel/WorkspacePointerTest.php
@@ -0,0 +1,109 @@
+<?php
+
+namespace Drupal\Tests\workspace\Kernel;
+
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\multiversion\Entity\Workspace;
+use Drupal\multiversion\Entity\WorkspaceInterface;
+use Drupal\multiversion\Entity\WorkspaceType;
+use Drupal\workspace\Entity\WorkspacePointer;
+
+/**
+ * Tests for the WorkspacePointer entity.
+ *
+ * @requires key_value
+ * @requires multiversion
+ *
+ * @group workspace
+ */
+class WorkspacePointerTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['workspace', 'multiversion', 'key_value', 'serialization', 'user', 'system'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+    $this->installEntitySchema('workspace');
+    $this->installEntitySchema('workspace_pointer');
+    $this->installEntitySchema('user');
+  }
+
+  /**
+   * Creates a workspace type for testing purposes.
+   *
+   * @return WorkspaceType
+   */
+  protected function createWorkspaceType() {
+    $workspace_type = WorkspaceType::create([
+      'id' => 'test',
+      'label' => 'Workspace bundle',
+    ]);
+    $workspace_type->save();
+
+    return $workspace_type;
+  }
+
+  /**
+   * Creates a workspace for testing purposes.
+   *
+   * @return WorkspaceInterface
+   */
+  protected function createWorkspace() {
+    $workspace = Workspace::create([
+      'type' => 'test',
+      'machine_name' => 'le_workspace',
+      'label' => 'Le Workspace',
+    ]);
+    $workspace->save();
+
+    return $workspace;
+  }
+
+  /**
+   * Verifies pointers can be created using an object as the reference.
+   */
+  public function testCreationWithObject() {
+    $this->createWorkspaceType();
+
+    $workspace = $this->createWorkspace();
+
+    /** @var WorkspacePointer $pointer */
+    $pointer = WorkspacePointer::create();
+    $pointer->setWorkspace($workspace);
+    $pointer->save();
+
+    $id = $pointer->id();
+
+    $pointer = WorkspacePointer::load($id);
+
+    $this->assertEquals($workspace->id(), $pointer->getWorkspaceId());
+    $this->assertEquals($workspace->id(), $pointer->getWorkspace()->id());
+  }
+
+  /**
+   * Verifies pointers can be created using an ID as the reference.
+   */
+  public function testCreationWithId() {
+    $this->createWorkspaceType();
+
+    $workspace = $this->createWorkspace();
+
+    /** @var WorkspacePointer $pointer */
+    $pointer = WorkspacePointer::create();
+    $pointer->setWorkspaceId($workspace->id());
+    $pointer->save();
+
+    $id = $pointer->id();
+
+    $pointer = WorkspacePointer::load($id);
+
+    $this->assertEquals($workspace->id(), $pointer->getWorkspaceId());
+    $this->assertEquals($workspace->id(), $pointer->getWorkspace()->id());
+  }
+}
diff --git a/workspace.info.yml b/workspace.info.yml
index ed7468c..b50e2e4 100644
--- a/workspace.info.yml
+++ b/workspace.info.yml
@@ -5,4 +5,5 @@ core: 8.x
 dependencies:
   - options
   - datetime
-  - multiversion
\ No newline at end of file
+  - multiversion
+  - dynamic_entity_reference
diff --git a/workspace.links.action.yml b/workspace.links.action.yml
index b2c6971..4bd599b 100644
--- a/workspace.links.action.yml
+++ b/workspace.links.action.yml
@@ -7,4 +7,4 @@ entity.workspace_type.add_form:
   route_name: 'entity.workspace_type.add_form'
   title: 'Add Workspace type'
   appears_on:
-    - entity.workspace_type.collection
\ No newline at end of file
+    - entity.workspace_type.collection
diff --git a/workspace.links.task.yml b/workspace.links.task.yml
index e7a8e84..e6f8cc2 100644
--- a/workspace.links.task.yml
+++ b/workspace.links.task.yml
@@ -16,4 +16,4 @@ entity.workspace_type.edit_form:
   route_name: entity.workspace_type.edit_form
   base_route: entity.workspace_type.edit_form
 workspace.revisions:
-  deriver: '\Drupal\workspace\Plugin\Derivative\RevisionsLocalTask'
\ No newline at end of file
+  deriver: '\Drupal\workspace\Plugin\Derivative\RevisionsLocalTask'
diff --git a/workspace.module b/workspace.module
index 66a090e..f2b9a0d 100644
--- a/workspace.module
+++ b/workspace.module
@@ -3,39 +3,20 @@
 use Drupal\Component\Utility\Unicode;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
-use Drupal\workspace\Pointer;
+use Drupal\multiversion\Entity\WorkspaceInterface;
 
 /**
  * Implements hook_entity_type_alter().
- *
- * @param \Drupal\Core\Entity\EntityTypeInterface[] $entity_types
  */
 function workspace_entity_type_alter(array &$entity_types) {
-  \Drupal::service('workspace.entity_type_alter')->entityTypeAlter($entity_types);
+  \Drupal::service('workspace.entity_type_info')->entityTypeAlter($entity_types);
 }
 
 /**
  * Implements hook_entity_base_field_info().
- * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
- * @return
  */
 function workspace_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
-  if ($entity_type->id() === 'workspace') {
-    $fields['upstream'] = \Drupal\Core\Field\BaseFieldDefinition::create('entity_reference')
-      ->setLabel(t('Assign default target workspace'))
-      ->setDescription(t('The workspace to push to and pull from.'))
-      ->setRevisionable(TRUE)
-      ->setRequired(TRUE)
-      ->setSetting('target_type', 'workspace')
-      ->setDefaultValueCallback('workspace_active_id')
-      ->setDisplayOptions('form', array(
-        'type' => 'options_buttons',
-        'weight' => 0
-      ))
-      ->setDisplayConfigurable('form', TRUE);
-
-    return $fields;
-  }
+  \Drupal::service('workspace.entity_type_info')->entityBaseFieldInfo($entity_type);
 }
 
 /**
@@ -46,7 +27,7 @@ function workspace_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterfac
 function workspace_active_id() {
   /** @var \Drupal\multiversion\Entity\Workspace $active_workspace */
   $active_workspace = \Drupal::service('workspace.manager')->getActiveWorkspace();
-  if ($active_workspace instanceof \Drupal\multiversion\Entity\Workspace) {
+  if ($active_workspace instanceof WorkspaceInterface) {
     return [$active_workspace->id()];
   }
 }
@@ -56,10 +37,8 @@ function workspace_active_id() {
  *
  * @param \Drupal\multiversion\Entity\WorkspaceInterface $workspace
  */
-function workspace_workspace_insert(\Drupal\multiversion\Entity\WorkspaceInterface $workspace) {
-  /** @var $pointer \Drupal\workspace\PointerInterface */
-  $pointer = new Pointer('workspace:' . $workspace->id(), $workspace->label(), ['workspace' => $workspace->id()]);
-  \Drupal::service('workspace.pointer')->add($pointer);
+function workspace_workspace_insert(WorkspaceInterface $workspace) {
+  \Drupal::service('workspace.entity_operations')->workspaceInsert($workspace);
 }
 
 function workspace_pointer_allowed_values(FieldStorageDefinitionInterface $definition, FieldableEntityInterface $entity = NULL, &$cacheable) {
diff --git a/workspace.routing.yml b/workspace.routing.yml
index 1f27918..b3b197d 100644
--- a/workspace.routing.yml
+++ b/workspace.routing.yml
@@ -56,4 +56,4 @@ entity.workspace_type.add_form:
   requirements:
     _permission: 'administer site configuration'
   options:
-    _admin_route: TRUE
\ No newline at end of file
+    _admin_route: TRUE
diff --git a/workspace.services.yml b/workspace.services.yml
index abd2928..58abf2c 100644
--- a/workspace.services.yml
+++ b/workspace.services.yml
@@ -8,12 +8,12 @@ services:
     arguments: ['@workspace.manager', '@multiversion.manager', '@entity_type.manager']
     tags:
       - {name: workspace_replicator, priority: 10}
-  workspace.pointer:
-    class: Drupal\workspace\WorkspacePointer
-    arguments: ['@keyvalue']
-  workspace.entity_type_alter:
-    class: Drupal\workspace\EntityTypeAlter
+  workspace.entity_type_info:
+    class: Drupal\workspace\EntityTypeInfo
     arguments: ['@multiversion.manager']
+  workspace.entity_operations:
+    class: Drupal\workspace\EntityOperations
+    arguments: ['@multiversion.manager', '@entity_type.manager']
   workspace.toolbar:
     class: Drupal\workspace\Toolbar
     arguments: ['@entity_type.manager', '@workspace.manager', '@form_builder']
@@ -29,6 +29,6 @@ services:
       - { name: paramconverter, priority: 30 }
   workspace.workbench_moderation_subscriber:
     class: Drupal\workspace\EventSubscriber\WorkbenchModerationSubscriber
-    arguments: ['@entity_type.manager', '@workspace.pointer', '@workspace.replicator_manager']
+    arguments: ['@entity_type.manager', '@workspace.replicator_manager']
     tags:
-      - { name: event_subscriber }
\ No newline at end of file
+      - { name: event_subscriber }
