diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 4d2a7f6cbf046029fdd728b3b81ebe9d67629735..c7b2937684da87cfbaf87fe1d9cfed737675f6fa 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1454,25 +1454,3 @@ function system_element_info_alter(&$type) {
     $type['page']['#theme_wrappers']['off_canvas_page_wrapper'] = ['#weight' => -1000];
   }
 }
-
-/**
- * Implements hook_modules_uninstalled().
- */
-function system_modules_uninstalled($modules) {
-  // @todo Remove this when modules are able to maintain their revision metadata
-  //   keys.
-  //   @see https://www.drupal.org/project/drupal/issues/3074333
-  if (!in_array('workspaces', $modules, TRUE)) {
-    return;
-  }
-
-  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
-  foreach ($entity_definition_update_manager->getEntityTypes() as $entity_type) {
-    $revision_metadata_keys = $entity_type->get('revision_metadata_keys');
-    if ($revision_metadata_keys && array_key_exists('workspace', $revision_metadata_keys)) {
-      unset($revision_metadata_keys['workspace']);
-      $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
-      $entity_definition_update_manager->updateEntityType($entity_type);
-    }
-  }
-}
diff --git a/core/modules/workspaces/src/Entity/WorkspaceAssociation.php b/core/modules/workspaces/src/Entity/WorkspaceAssociation.php
new file mode 100644
index 0000000000000000000000000000000000000000..6c65c81ed024c60b426fee0955dc4fcbf48bfb71
--- /dev/null
+++ b/core/modules/workspaces/src/Entity/WorkspaceAssociation.php
@@ -0,0 +1,77 @@
+<?php
+
+namespace Drupal\workspaces\Entity;
+
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines the Workspace association entity.
+ *
+ * @ContentEntityType(
+ *   id = "workspace_association",
+ *   label = @Translation("Workspace association"),
+ *   label_collection = @Translation("Workspace associations"),
+ *   label_singular = @Translation("workspace association"),
+ *   label_plural = @Translation("workspace associations"),
+ *   label_count = @PluralTranslation(
+ *     singular = "@count workspace association",
+ *     plural = "@count workspace associations"
+ *   ),
+ *   handlers = {
+ *     "storage" = "Drupal\workspaces\WorkspaceAssociationStorage"
+ *   },
+ *   base_table = "workspace_association",
+ *   revision_table = "workspace_association_revision",
+ *   internal = TRUE,
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "revision" = "revision_id",
+ *     "uuid" = "uuid",
+ *   }
+ * )
+ *
+ * @internal
+ *   This entity is marked internal because it should not be used directly to
+ *   alter the workspace an entity belongs to.
+ */
+class WorkspaceAssociation extends ContentEntityBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+    $fields = parent::baseFieldDefinitions($entity_type);
+
+    $fields['workspace'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(new TranslatableMarkup('workspace'))
+      ->setDescription(new TranslatableMarkup('The workspace of the referenced content.'))
+      ->setSetting('target_type', 'workspace')
+      ->setRequired(TRUE)
+      ->setRevisionable(TRUE);
+
+    $fields['target_entity_type_id'] = BaseFieldDefinition::create('string')
+      ->setLabel(new TranslatableMarkup('Content entity type ID'))
+      ->setDescription(new TranslatableMarkup('The ID of the content entity type associated with this workspace.'))
+      ->setSetting('max_length', EntityTypeInterface::ID_MAX_LENGTH)
+      ->setRequired(TRUE)
+      ->setRevisionable(TRUE);
+
+    $fields['target_entity_id'] = BaseFieldDefinition::create('integer')
+      ->setLabel(new TranslatableMarkup('Content entity ID'))
+      ->setDescription(new TranslatableMarkup('The ID of the content entity associated with this workspace.'))
+      ->setRequired(TRUE)
+      ->setRevisionable(TRUE);
+
+    $fields['target_entity_revision_id'] = BaseFieldDefinition::create('integer')
+      ->setLabel(new TranslatableMarkup('Content entity revision ID'))
+      ->setDescription(new TranslatableMarkup('The revision ID of the content entity associated with this workspace.'))
+      ->setRequired(TRUE)
+      ->setRevisionable(TRUE);
+
+    return $fields;
+  }
+
+}
diff --git a/core/modules/workspaces/src/EntityOperations.php b/core/modules/workspaces/src/EntityOperations.php
index 4409162a282b2dcd967bed2286af0f6c14f222b7..6182da200f2cbc7606a7d0071f0e3c90741e67b6 100644
--- a/core/modules/workspaces/src/EntityOperations.php
+++ b/core/modules/workspaces/src/EntityOperations.php
@@ -34,13 +34,6 @@ class EntityOperations implements ContainerInjectionInterface {
    */
   protected $workspaceManager;
 
-  /**
-   * The workspace association service.
-   *
-   * @var \Drupal\workspaces\WorkspaceAssociationInterface
-   */
-  protected $workspaceAssociation;
-
   /**
    * Constructs a new EntityOperations instance.
    *
@@ -48,13 +41,10 @@ class EntityOperations implements ContainerInjectionInterface {
    *   The entity type manager service.
    * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
    *   The workspace manager service.
-   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
-   *   The workspace association service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, WorkspaceManagerInterface $workspace_manager) {
     $this->entityTypeManager = $entity_type_manager;
     $this->workspaceManager = $workspace_manager;
-    $this->workspaceAssociation = $workspace_association;
   }
 
   /**
@@ -63,8 +53,7 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Wor
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity_type.manager'),
-      $container->get('workspaces.manager'),
-      $container->get('workspaces.association')
+      $container->get('workspaces.manager')
     );
   }
 
@@ -85,13 +74,31 @@ public function entityPreload(array $ids, $entity_type_id) {
     // Get a list of revision IDs for entities that have a revision set for the
     // current active workspace. If an entity has multiple revisions set for a
     // workspace, only the one with the highest ID is returned.
-    if ($tracked_entities = $this->workspaceAssociation->getTrackedEntities($this->workspaceManager->getActiveWorkspace()->id(), $entity_type_id, $ids)) {
+    $max_revision_id = 'max_target_entity_revision_id';
+    $query = $this->entityTypeManager
+      ->getStorage('workspace_association')
+      ->getAggregateQuery()
+      ->accessCheck(FALSE)
+      ->allRevisions()
+      ->aggregate('target_entity_revision_id', 'MAX', NULL, $max_revision_id)
+      ->groupBy('target_entity_id')
+      ->condition('target_entity_type_id', $entity_type_id)
+      ->condition('workspace', $this->workspaceManager->getActiveWorkspace()->id());
+
+    if ($ids) {
+      $query->condition('target_entity_id', $ids, 'IN');
+    }
+
+    $results = $query->execute();
+
+    if ($results) {
       /** @var \Drupal\Core\Entity\RevisionableStorageInterface $storage */
       $storage = $this->entityTypeManager->getStorage($entity_type_id);
 
       // Swap out every entity which has a revision set for the current active
       // workspace.
-      foreach ($storage->loadMultipleRevisions(array_keys($tracked_entities[$entity_type_id])) as $revision) {
+      $swap_revision_ids = array_column($results, $max_revision_id);
+      foreach ($storage->loadMultipleRevisions($swap_revision_ids) as $revision) {
         $entities[$revision->id()] = $revision;
       }
     }
@@ -135,10 +142,6 @@ public function entityPresave(EntityInterface $entity) {
       // become the default revision only when it is replicated to the default
       // workspace.
       $entity->isDefaultRevision(FALSE);
-
-      // Track the workspaces in which the new revision was saved.
-      $field_name = $entity_type->getRevisionMetadataKey('workspace');
-      $entity->{$field_name}->target_id = $this->workspaceManager->getActiveWorkspace()->id();
     }
 
     // When a new published entity is inserted in a non-default workspace, we
@@ -171,7 +174,7 @@ public function entityInsert(EntityInterface $entity) {
       return;
     }
 
-    $this->workspaceAssociation->trackEntity($entity, $this->workspaceManager->getActiveWorkspace());
+    $this->trackEntity($entity);
 
     // When an entity is newly created in a workspace, it should be published in
     // that workspace, but not yet published on the live workspace. It is first
@@ -208,7 +211,7 @@ public function entityUpdate(EntityInterface $entity) {
     // Only track new revisions.
     /** @var \Drupal\Core\Entity\RevisionableInterface $entity */
     if ($entity->getLoadedRevisionId() != $entity->getRevisionId()) {
-      $this->workspaceAssociation->trackEntity($entity, $this->workspaceManager->getActiveWorkspace());
+      $this->trackEntity($entity);
     }
   }
 
@@ -237,6 +240,51 @@ public function entityPredelete(EntityInterface $entity) {
     }
   }
 
+  /**
+   * Updates or creates a WorkspaceAssociation entity for a given entity.
+   *
+   * If the passed-in entity can belong to a workspace and already has a
+   * WorkspaceAssociation entity, then a new revision of this will be created with
+   * the new information. Otherwise, a new WorkspaceAssociation entity is created to
+   * store the passed-in entity's information.
+   *
+   * @param \Drupal\Core\Entity\RevisionableInterface $entity
+   *   The entity to update or create from.
+   */
+  protected function trackEntity(RevisionableInterface $entity) {
+    // If the entity is not new, check if there's an existing
+    // WorkspaceAssociation entity for it.
+    $workspace_association_storage = $this->entityTypeManager->getStorage('workspace_association');
+    if (!$entity->isNew()) {
+      $workspace_associations = $workspace_association_storage->loadByProperties([
+        'target_entity_type_id' => $entity->getEntityTypeId(),
+        'target_entity_id' => $entity->id(),
+      ]);
+
+      /** @var \Drupal\Core\Entity\ContentEntityInterface $workspace_association */
+      $workspace_association = reset($workspace_associations);
+    }
+
+    // If there was a WorkspaceAssociation entry create a new revision,
+    // otherwise create a new entity with the type and ID.
+    if (!empty($workspace_association)) {
+      $workspace_association->setNewRevision(TRUE);
+    }
+    else {
+      $workspace_association = $workspace_association_storage->create([
+        'target_entity_type_id' => $entity->getEntityTypeId(),
+        'target_entity_id' => $entity->id(),
+      ]);
+    }
+
+    // Add the revision ID and the workspace ID.
+    $workspace_association->set('target_entity_revision_id', $entity->getRevisionId());
+    $workspace_association->set('workspace', $this->workspaceManager->getActiveWorkspace()->id());
+
+    // Save without updating the tracked content entity.
+    $workspace_association->save();
+  }
+
   /**
    * Alters entity forms to disallow concurrent editing in multiple workspaces.
    *
@@ -250,7 +298,7 @@ public function entityPredelete(EntityInterface $entity) {
    * @see hook_form_alter()
    */
   public function entityFormAlter(array &$form, FormStateInterface $form_state, $form_id) {
-    /** @var \Drupal\Core\Entity\RevisionableInterface $entity */
+    /** @var \Drupal\Core\Entity\EntityInterface $entity */
     $entity = $form_state->getFormObject()->getEntity();
     if (!$this->workspaceManager->isEntityTypeSupported($entity->getEntityType())) {
       return;
@@ -270,7 +318,9 @@ public function entityFormAlter(array &$form, FormStateInterface $form_state, $f
       $form['#entity_builders'][] = [get_called_class(), 'entityFormEntityBuild'];
     }
 
-    if ($workspace_ids = $this->workspaceAssociation->getEntityTrackingWorkspaceIds($entity)) {
+    /** @var \Drupal\workspaces\WorkspaceAssociationStorageInterface $workspace_association_storage */
+    $workspace_association_storage = $this->entityTypeManager->getStorage('workspace_association');
+    if ($workspace_ids = $workspace_association_storage->getEntityTrackingWorkspaceIds($entity)) {
       // An entity can only be edited in one workspace.
       $workspace_id = reset($workspace_ids);
 
diff --git a/core/modules/workspaces/src/EntityTypeInfo.php b/core/modules/workspaces/src/EntityTypeInfo.php
index 7a72eb246d26cc8beefb42fc5000599e04bb53e1..5495c7fa4e7c09c31db6484bc881ad7126279341 100644
--- a/core/modules/workspaces/src/EntityTypeInfo.php
+++ b/core/modules/workspaces/src/EntityTypeInfo.php
@@ -3,10 +3,7 @@
 namespace Drupal\workspaces;
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -69,10 +66,6 @@ public function entityTypeBuild(array &$entity_types) {
     foreach ($entity_types as $entity_type) {
       if ($this->workspaceManager->isEntityTypeSupported($entity_type)) {
         $entity_type->addConstraint('EntityWorkspaceConflict');
-
-        $revision_metadata_keys = $entity_type->get('revision_metadata_keys');
-        $revision_metadata_keys['workspace'] = 'workspace';
-        $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
       }
     }
   }
@@ -91,30 +84,4 @@ public function fieldInfoAlter(&$definitions) {
     }
   }
 
-  /**
-   * Provides custom base field definitions for a content entity type.
-   *
-   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
-   *   The entity type definition.
-   *
-   * @return \Drupal\Core\Field\FieldDefinitionInterface[]
-   *   An array of field definitions, keyed by field name.
-   *
-   * @see hook_entity_base_field_info()
-   */
-  public function entityBaseFieldInfo(EntityTypeInterface $entity_type) {
-    if ($this->workspaceManager->isEntityTypeSupported($entity_type)) {
-      $field_name = $entity_type->getRevisionMetadataKey('workspace');
-      $fields[$field_name] = BaseFieldDefinition::create('entity_reference')
-        ->setLabel(new TranslatableMarkup('Workspace'))
-        ->setDescription(new TranslatableMarkup('Indicates the workspace that this revision belongs to.'))
-        ->setSetting('target_type', 'workspace')
-        ->setInternal(TRUE)
-        ->setTranslatable(FALSE)
-        ->setRevisionable(TRUE);
-
-      return $fields;
-    }
-  }
-
 }
diff --git a/core/modules/workspaces/src/EventSubscriber/EntitySchemaSubscriber.php b/core/modules/workspaces/src/EventSubscriber/EntitySchemaSubscriber.php
deleted file mode 100644
index 30fd77aa6445cca0ed96aacd74acaef04a63c299..0000000000000000000000000000000000000000
--- a/core/modules/workspaces/src/EventSubscriber/EntitySchemaSubscriber.php
+++ /dev/null
@@ -1,147 +0,0 @@
-<?php
-
-namespace Drupal\workspaces\EventSubscriber;
-
-use Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface;
-use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
-use Drupal\Core\Entity\EntityTypeEventSubscriberTrait;
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Entity\EntityTypeListenerInterface;
-use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
-use Drupal\workspaces\WorkspaceManagerInterface;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * Defines a class for listening to entity schema changes.
- */
-class EntitySchemaSubscriber implements EntityTypeListenerInterface, EventSubscriberInterface {
-
-  use EntityTypeEventSubscriberTrait;
-  use StringTranslationTrait;
-
-  /**
-   * The definition update manager.
-   *
-   * @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
-   */
-  protected $entityDefinitionUpdateManager;
-
-  /**
-   * The last installed schema definitions.
-   *
-   * @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
-   */
-  protected $entityLastInstalledSchemaRepository;
-
-  /**
-   * The workspace manager.
-   *
-   * @var \Drupal\workspaces\WorkspaceManagerInterface
-   */
-  protected $workspaceManager;
-
-  /**
-   * Constructs a new EntitySchemaSubscriber.
-   *
-   * @param \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface $entityDefinitionUpdateManager
-   *   Definition update manager.
-   * @param \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entityLastInstalledSchemaRepository
-   *   Last definitions.
-   * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
-   *   The workspace manager.
-   */
-  public function __construct(EntityDefinitionUpdateManagerInterface $entityDefinitionUpdateManager, EntityLastInstalledSchemaRepositoryInterface $entityLastInstalledSchemaRepository, WorkspaceManagerInterface $workspace_manager) {
-    $this->entityDefinitionUpdateManager = $entityDefinitionUpdateManager;
-    $this->entityLastInstalledSchemaRepository = $entityLastInstalledSchemaRepository;
-    $this->workspaceManager = $workspace_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function getSubscribedEvents() {
-    return static::getEntityTypeEvents();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function onEntityTypeCreate(EntityTypeInterface $entity_type) {
-    // Nothing to do here.
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function onEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeInterface $original) {
-    // If the entity type is now supported by Workspaces, add the revision
-    // metadata field.
-    if ($this->workspaceManager->isEntityTypeSupported($entity_type) && !$this->workspaceManager->isEntityTypeSupported($original)) {
-      $revision_metadata_keys = $entity_type->get('revision_metadata_keys');
-
-      if (!isset($revision_metadata_keys['workspace'])) {
-        // Bail out if there's an existing field called 'workspace'.
-        if ($this->entityDefinitionUpdateManager->getFieldStorageDefinition('workspace', $entity_type->id())) {
-          throw new \RuntimeException("An existing 'workspace' field was found for the '{$entity_type->id()}' entity type. Set the 'workspace' revision metadata key to use a different field name and run this update function again.");
-        }
-
-        $revision_metadata_keys['workspace'] = 'workspace';
-        $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
-
-        // We are only adding a revision metadata key so we don't need to go
-        // through the entity update process.
-        $this->entityLastInstalledSchemaRepository->setLastInstalledDefinition($entity_type);
-      }
-
-      $this->entityDefinitionUpdateManager->installFieldStorageDefinition($revision_metadata_keys['workspace'], $entity_type->id(), 'workspaces', $this->getWorkspaceFieldDefinition());
-    }
-
-    // If the entity type is no longer supported by Workspaces, remove the
-    // revision metadata field.
-    if ($this->workspaceManager->isEntityTypeSupported($original) && !$this->workspaceManager->isEntityTypeSupported($entity_type)) {
-      $revision_metadata_keys = $original->get('revision_metadata_keys');
-      $field_storage_definition = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type->id())[$revision_metadata_keys['workspace']];
-      $this->entityDefinitionUpdateManager->uninstallFieldStorageDefinition($field_storage_definition);
-
-      $revision_metadata_keys = $entity_type->get('revision_metadata_keys');
-      unset($revision_metadata_keys['workspace']);
-      $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
-
-      // We are only removing a revision metadata key so we don't need to go
-      // through the entity update process.
-      $this->entityLastInstalledSchemaRepository->setLastInstalledDefinition($entity_type);
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function onFieldableEntityTypeUpdate(EntityTypeInterface $entity_type, EntityTypeInterface $original, array $field_storage_definitions, array $original_field_storage_definitions, array &$sandbox = NULL) {
-    $this->onEntityTypeUpdate($entity_type, $original);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function onEntityTypeDelete(EntityTypeInterface $entity_type) {
-    // Nothing to do here.
-  }
-
-  /**
-   * Gets the base field definition for the 'workspace' revision metadata field.
-   *
-   * @return \Drupal\Core\Field\BaseFieldDefinition
-   *   The base field definition.
-   */
-  protected function getWorkspaceFieldDefinition() {
-    return BaseFieldDefinition::create('entity_reference')
-      ->setLabel($this->t('Workspace'))
-      ->setDescription($this->t('Indicates the workspace that this revision belongs to.'))
-      ->setSetting('target_type', 'workspace')
-      ->setInternal(TRUE)
-      ->setTranslatable(FALSE)
-      ->setRevisionable(TRUE);
-  }
-
-}
diff --git a/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php b/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php
index 195cac732fd28135267597680714a079850962a9..8086873f9ade48b67d544f764fdbc7b1b9aaaf04 100644
--- a/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php
+++ b/core/modules/workspaces/src/Form/WorkspaceDeleteForm.php
@@ -2,13 +2,8 @@
 
 namespace Drupal\workspaces\Form;
 
-use Drupal\Component\Datetime\TimeInterface;
 use Drupal\Core\Entity\ContentEntityDeleteForm;
-use Drupal\Core\Entity\EntityRepositoryInterface;
-use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\workspaces\WorkspaceAssociationInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a form for deleting a workspace.
@@ -24,52 +19,14 @@ class WorkspaceDeleteForm extends ContentEntityDeleteForm implements WorkspaceFo
    */
   protected $entity;
 
-  /**
-   * The workspace association service.
-   *
-   * @var \Drupal\workspaces\WorkspaceAssociationInterface
-   */
-  protected $workspaceAssociation;
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('entity.repository'),
-      $container->get('workspaces.association'),
-      $container->get('entity_type.bundle.info'),
-      $container->get('datetime.time')
-    );
-  }
-
-  /**
-   * Constructs a WorkspaceDeleteForm object.
-   *
-   * @param \Drupal\Core\Entity\EntityRepositoryInterface $entity_repository
-   *   The entity repository service.
-   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
-   *   The workspace association service to check how many revisions will be
-   *   deleted.
-   * @param \Drupal\Core\Entity\EntityTypeBundleInfoInterface $entity_type_bundle_info
-   *   The entity type bundle service.
-   * @param \Drupal\Component\Datetime\TimeInterface $time
-   *   The time service.
-   */
-  public function __construct(EntityRepositoryInterface $entity_repository, WorkspaceAssociationInterface $workspace_association, EntityTypeBundleInfoInterface $entity_type_bundle_info = NULL, TimeInterface $time = NULL) {
-    parent::__construct($entity_repository, $entity_type_bundle_info, $time);
-    $this->workspaceAssociation = $workspace_association;
-  }
-
   /**
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
     $form = parent::buildForm($form, $form_state);
-    $tracked_entities = $this->workspaceAssociation->getTrackedEntities($this->entity->id());
+    $source_rev_diff = $this->entityTypeManager->getStorage('workspace_association')->getTrackedEntities($this->entity->id());
     $items = [];
-    foreach (array_keys($tracked_entities) as $entity_type_id => $entity_ids) {
-      $revision_ids = $this->workspaceAssociation->getAssociatedRevisions($this->entity->id(), $entity_type_id, $entity_ids);
+    foreach ($source_rev_diff as $entity_type_id => $revision_ids) {
       $label = $this->entityTypeManager->getDefinition($entity_type_id)->getLabel();
       $items[] = $this->formatPlural(count($revision_ids), '1 @label revision.', '@count @label revisions.', ['@label' => $label]);
     }
diff --git a/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraintValidator.php b/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraintValidator.php
index 1543b5fc2b30fca4e9499667221522f25b39b2bc..070e89050bb8adae926b7336766230b72be792cf 100644
--- a/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraintValidator.php
+++ b/core/modules/workspaces/src/Plugin/Validation/Constraint/DeletedWorkspaceConstraintValidator.php
@@ -3,7 +3,7 @@
 namespace Drupal\workspaces\Plugin\Validation\Constraint;
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
-use Drupal\workspaces\WorkspaceAssociationInterface;
+use Drupal\workspaces\WorkspaceAssociationStorageInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Validator\Constraint;
 use Symfony\Component\Validator\ConstraintValidator;
@@ -14,20 +14,20 @@
 class DeletedWorkspaceConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
 
   /**
-   * The workspace association service.
+   * The workspace association storage.
    *
-   * @var \Drupal\workspaces\WorkspaceAssociationInterface
+   * @var \Drupal\workspaces\WorkspaceAssociationStorageInterface
    */
-  protected $workspaceAssociation;
+  protected $workspaceAssociationStorage;
 
   /**
    * Creates a new DeletedWorkspaceConstraintValidator instance.
    *
-   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
-   *   The workspace association service.
+   * @param \Drupal\workspaces\WorkspaceAssociationStorageInterface $workspace_association_storage
+   *   The workspace association storage.
    */
-  public function __construct(WorkspaceAssociationInterface $workspace_association) {
-    $this->workspaceAssociation = $workspace_association;
+  public function __construct(WorkspaceAssociationStorageInterface $workspace_association_storage) {
+    $this->workspaceAssociationStorage = $workspace_association_storage;
   }
 
   /**
@@ -35,7 +35,7 @@ public function __construct(WorkspaceAssociationInterface $workspace_association
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('workspaces.association')
+      $container->get('entity_type.manager')->getStorage('workspace_association')
     );
   }
 
@@ -49,7 +49,14 @@ public function validate($value, Constraint $constraint) {
       return;
     }
 
-    if ($this->workspaceAssociation->getTrackedEntities($value->getEntity()->id())) {
+    $count = $this->workspaceAssociationStorage
+      ->getQuery()
+      ->allRevisions()
+      ->accessCheck(FALSE)
+      ->condition('workspace', $value->getEntity()->id())
+      ->count()
+      ->execute();
+    if ($count) {
       $this->context->addViolation($constraint->message);
     }
   }
diff --git a/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraintValidator.php b/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraintValidator.php
index 66bb887e7b1243ee6047817035d75063826a6e62..17adc7c0d2d892930b2f3904f0a9758ce2cacca5 100644
--- a/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraintValidator.php
+++ b/core/modules/workspaces/src/Plugin/Validation/Constraint/EntityWorkspaceConflictConstraintValidator.php
@@ -4,7 +4,6 @@
 
 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\workspaces\WorkspaceAssociationInterface;
 use Drupal\workspaces\WorkspaceManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\Validator\Constraint;
@@ -29,13 +28,6 @@ class EntityWorkspaceConflictConstraintValidator extends ConstraintValidator imp
    */
   protected $workspaceManager;
 
-  /**
-   * The workspace association service.
-   *
-   * @var \Drupal\workspaces\WorkspaceAssociationInterface
-   */
-  protected $workspaceAssociation;
-
   /**
    * Constructs an EntityUntranslatableFieldsConstraintValidator object.
    *
@@ -43,13 +35,10 @@ class EntityWorkspaceConflictConstraintValidator extends ConstraintValidator imp
    *   The entity type manager service.
    * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
    *   The workspace manager service.
-   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
-   *   The workspace association service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, WorkspaceManagerInterface $workspace_manager) {
     $this->entityTypeManager = $entity_type_manager;
     $this->workspaceManager = $workspace_manager;
-    $this->workspaceAssociation = $workspace_association;
   }
 
   /**
@@ -58,8 +47,7 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Wor
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('entity_type.manager'),
-      $container->get('workspaces.manager'),
-      $container->get('workspaces.association')
+      $container->get('workspaces.manager')
     );
   }
 
@@ -69,7 +57,9 @@ public static function create(ContainerInterface $container) {
   public function validate($entity, Constraint $constraint) {
     /** @var \Drupal\Core\Entity\EntityInterface $entity */
     if (isset($entity) && !$entity->isNew()) {
-      $workspace_ids = $this->workspaceAssociation->getEntityTrackingWorkspaceIds($entity);
+      /** @var \Drupal\workspaces\WorkspaceAssociationStorageInterface $workspace_association_storage */
+      $workspace_association_storage = $this->entityTypeManager->getStorage('workspace_association');
+      $workspace_ids = $workspace_association_storage->getEntityTrackingWorkspaceIds($entity);
       $active_workspace = $this->workspaceManager->getActiveWorkspace();
 
       if ($workspace_ids && (!$active_workspace || !in_array($active_workspace->id(), $workspace_ids, TRUE))) {
diff --git a/core/modules/workspaces/src/WorkspaceAssociation.php b/core/modules/workspaces/src/WorkspaceAssociation.php
deleted file mode 100644
index a67f9546937278b9aaa16adcafe0cbf917cbaae8..0000000000000000000000000000000000000000
--- a/core/modules/workspaces/src/WorkspaceAssociation.php
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-
-namespace Drupal\workspaces;
-
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Entity\RevisionableInterface;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
-
-/**
- * Provides a class for CRUD operations on workspace associations.
- */
-class WorkspaceAssociation implements WorkspaceAssociationInterface {
-
-  /**
-   * The table for the workspace association storage.
-   */
-  const TABLE = 'workspace_association';
-
-  /**
-   * The database connection.
-   *
-   * @var \Drupal\Core\Database\Connection
-   */
-  protected $database;
-
-  /**
-   * The entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
-   */
-  protected $entityTypeManager;
-
-  /**
-   * Constructs a WorkspaceAssociation object.
-   *
-   * @param \Drupal\Core\Database\Connection $connection
-   *   A database connection for reading and writing path aliases.
-   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
-   *   The entity type manager for querying revisions.
-   */
-  public function __construct(Connection $connection, EntityTypeManagerInterface $entity_type_manager) {
-    $this->database = $connection;
-    $this->entityTypeManager = $entity_type_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function trackEntity(RevisionableInterface $entity, WorkspaceInterface $workspace) {
-    $this->database->merge(static::TABLE)
-      ->fields([
-        'target_entity_revision_id' => $entity->getRevisionId(),
-      ])
-      ->keys([
-        'workspace' => $workspace->id(),
-        'target_entity_type_id' => $entity->getEntityTypeId(),
-        'target_entity_id' => $entity->id(),
-      ])
-      ->execute();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getTrackedEntities($workspace_id, $entity_type_id = NULL, $entity_ids = NULL) {
-    $query = $this->database->select(static::TABLE);
-    $query
-      ->fields(static::TABLE, ['target_entity_type_id', 'target_entity_id', 'target_entity_revision_id'])
-      ->orderBy('target_entity_revision_id', 'ASC')
-      ->condition('workspace', $workspace_id);
-
-    if ($entity_type_id) {
-      $query->condition('target_entity_type_id', $entity_type_id, '=');
-
-      if ($entity_ids) {
-        $query->condition('target_entity_id', $entity_ids, 'IN');
-      }
-    }
-
-    $tracked_revisions = [];
-    foreach ($query->execute() as $record) {
-      $tracked_revisions[$record->target_entity_type_id][$record->target_entity_revision_id] = $record->target_entity_id;
-    }
-
-    return $tracked_revisions;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getAssociatedRevisions($workspace_id, $entity_type_id, $entity_ids = NULL) {
-    /** @var \Drupal\Core\Entity\EntityStorageInterface $storage */
-    $storage = $this->entityTypeManager->getStorage($entity_type_id);
-
-    // If the entity type is not using core's default entity storage, we can't
-    // assume the table mapping layout so we have to return only the latest
-    // tracked revisions.
-    if (!$storage instanceof SqlContentEntityStorage) {
-      return $this->getTrackedEntities($workspace_id, $entity_type_id, $entity_ids)[$entity_type_id];
-    }
-
-    $entity_type = $storage->getEntityType();
-    $table_mapping = $storage->getTableMapping();
-    $workspace_field = $table_mapping->getColumnNames($entity_type->get('revision_metadata_keys')['workspace'])['target_id'];
-    $id_field = $table_mapping->getColumnNames($entity_type->getKey('id'))['value'];
-    $revision_id_field = $table_mapping->getColumnNames($entity_type->getKey('revision'))['value'];
-
-    $query = $this->database->select($entity_type->getRevisionTable(), 'revision');
-    $query->leftJoin($entity_type->getBaseTable(), 'base', "revision.$id_field = base.$id_field");
-
-    $query
-      ->fields('revision', [$revision_id_field, $id_field])
-      ->condition("revision.$workspace_field", $workspace_id)
-      ->where("revision.$revision_id_field > base.$revision_id_field")
-      ->orderBy("revision.$revision_id_field", 'ASC');
-
-    // Restrict the result to a set of entity ID's if provided.
-    if ($entity_ids) {
-      $query->condition("revision.$id_field", $entity_ids, 'IN');
-    }
-
-    return $query->execute()->fetchAllKeyed();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getEntityTrackingWorkspaceIds(RevisionableInterface $entity) {
-    $query = $this->database->select(static::TABLE)
-      ->fields(static::TABLE, ['workspace'])
-      ->condition('target_entity_type_id', $entity->getEntityTypeId())
-      ->condition('target_entity_id', $entity->id());
-
-    return $query->execute()->fetchCol();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function postPublish(WorkspaceInterface $workspace) {
-    $this->deleteAssociations($workspace->id());
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function deleteAssociations($workspace_id, $entity_type_id = NULL, $entity_ids = NULL) {
-    $query = $this->database->delete(static::TABLE)
-      ->condition('workspace', $workspace_id);
-
-    if ($entity_type_id) {
-      $query->condition('target_entity_type_id', $entity_type_id, '=');
-
-      if ($entity_ids) {
-        $query->condition('target_entity_id', $entity_ids, 'IN');
-      }
-    }
-
-    $query->execute();
-  }
-
-}
diff --git a/core/modules/workspaces/src/WorkspaceAssociationInterface.php b/core/modules/workspaces/src/WorkspaceAssociationInterface.php
deleted file mode 100644
index 1c93ca4aaa197bc8320cc7c9465dff9dc34ab64c..0000000000000000000000000000000000000000
--- a/core/modules/workspaces/src/WorkspaceAssociationInterface.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-namespace Drupal\workspaces;
-
-use Drupal\Core\Entity\RevisionableInterface;
-
-/**
- * Defines an interface for the workspace_association service.
- *
- * The canonical workspace association data is stored in a revision metadata
- * field on each entity revision that is tracked by a workspace.
- *
- * For the purpose of optimizing workspace-specific queries, the default
- * implementation of this interface defines a custom 'workspace_association'
- * index table which stores only the latest revisions tracked by a workspace.
- *
- * @internal
- */
-interface WorkspaceAssociationInterface {
-
-  /**
-   * Updates or creates the association for a given entity and a workspace.
-   *
-   * @param \Drupal\Core\Entity\RevisionableInterface $entity
-   *   The entity to update or create from.
-   * @param \Drupal\workspaces\WorkspaceInterface $workspace
-   *   The workspace in which the entity will be tracked.
-   */
-  public function trackEntity(RevisionableInterface $entity, WorkspaceInterface $workspace);
-
-  /**
-   * Retrieves the entities tracked by a given workspace.
-   *
-   * @param string $workspace_id
-   *   The ID of the workspace.
-   * @param string|null $entity_type_id
-   *   (optional) An entity type ID to filter the results by. Defaults to NULL.
-   * @param int[]|string[]|null $entity_ids
-   *   (optional) An array of entity IDs to filter the results by. Defaults to
-   *   NULL.
-   *
-   * @return array
-   *   Returns a multidimensional array where the first level keys are entity
-   *   type IDs and the values are an array of entity IDs keyed by revision IDs.
-   */
-  public function getTrackedEntities($workspace_id, $entity_type_id = NULL, $entity_ids = NULL);
-
-  /**
-   * Retrieves all content revisions tracked by a given workspace.
-   *
-   * Since the 'workspace_association' index table only tracks the latest
-   * associated revisions, this method retrieves all the tracked revisions by
-   * querying the entity type's revision table directly.
-   *
-   * @param string $workspace_id
-   *   The ID of the workspace.
-   * @param string $entity_type_id
-   *   An entity type ID to find revisions for.
-   * @param int[]|string[]|null $entity_ids
-   *   (optional) An array of entity IDs to filter the results by. Defaults to
-   *   NULL.
-   *
-   * @return array
-   *   Returns an array where the values are an array of entity IDs keyed by
-   *   revision IDs.
-   */
-  public function getAssociatedRevisions($workspace_id, $entity_type_id, $entity_ids = NULL);
-
-  /**
-   * Gets a list of workspace IDs in which an entity is tracked.
-   *
-   * @param \Drupal\Core\Entity\RevisionableInterface $entity
-   *   An entity object.
-   *
-   * @return string[]
-   *   An array of workspace IDs where the given entity is tracked, or an empty
-   *   array if it is not tracked anywhere.
-   */
-  public function getEntityTrackingWorkspaceIds(RevisionableInterface $entity);
-
-  /**
-   * Triggers clean-up operations after publishing a workspace.
-   *
-   * @param \Drupal\workspaces\WorkspaceInterface $workspace
-   *   A workspace entity.
-   */
-  public function postPublish(WorkspaceInterface $workspace);
-
-  /**
-   * Deletes all the workspace association records for the given workspace.
-   *
-   * @param string $workspace_id
-   *   A workspace entity ID.
-   * @param string|null $entity_type_id
-   *   (optional) The target entity type of the associations to delete. Defaults
-   *   to NULL.
-   * @param string|null $entity_ids
-   *   (optional) The target entity IDs of the associations to delete. Defaults
-   *   to NULL.
-   */
-  public function deleteAssociations($workspace_id, $entity_type_id = NULL, $entity_ids = NULL);
-
-}
diff --git a/core/modules/workspaces/src/WorkspaceAssociationStorage.php b/core/modules/workspaces/src/WorkspaceAssociationStorage.php
new file mode 100644
index 0000000000000000000000000000000000000000..6355e79220e49aa51251fcf1a9bb033e473ce393
--- /dev/null
+++ b/core/modules/workspaces/src/WorkspaceAssociationStorage.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Drupal\workspaces;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+
+/**
+ * Defines the storage handler class for the Workspace association entity type.
+ */
+class WorkspaceAssociationStorage extends SqlContentEntityStorage implements WorkspaceAssociationStorageInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function postPush(WorkspaceInterface $workspace) {
+    $this->database
+      ->delete($this->entityType->getBaseTable())
+      ->condition('workspace', $workspace->id())
+      ->execute();
+    $this->database
+      ->delete($this->entityType->getRevisionTable())
+      ->condition('workspace', $workspace->id())
+      ->execute();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTrackedEntities($workspace_id, $all_revisions = FALSE) {
+    $table = $all_revisions ? $this->getRevisionTable() : $this->getBaseTable();
+    $query = $this->database->select($table, 'base_table');
+    $query
+      ->fields('base_table', ['target_entity_type_id', 'target_entity_id', 'target_entity_revision_id'])
+      ->orderBy('target_entity_revision_id', 'ASC')
+      ->condition('workspace', $workspace_id);
+
+    $tracked_revisions = [];
+    foreach ($query->execute() as $record) {
+      $tracked_revisions[$record->target_entity_type_id][$record->target_entity_revision_id] = $record->target_entity_id;
+    }
+
+    return $tracked_revisions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getEntityTrackingWorkspaceIds(EntityInterface $entity) {
+    $query = $this->database->select($this->getBaseTable(), 'base_table');
+    $query
+      ->fields('base_table', ['workspace'])
+      ->condition('target_entity_type_id', $entity->getEntityTypeId())
+      ->condition('target_entity_id', $entity->id());
+
+    return $query->execute()->fetchCol();
+  }
+
+}
diff --git a/core/modules/workspaces/src/WorkspaceAssociationStorageInterface.php b/core/modules/workspaces/src/WorkspaceAssociationStorageInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..24663206e30c6d33e04f75e75af8986c8462dc8c
--- /dev/null
+++ b/core/modules/workspaces/src/WorkspaceAssociationStorageInterface.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\workspaces;
+
+use Drupal\Core\Entity\ContentEntityStorageInterface;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines an interface for workspace association entity storage classes.
+ */
+interface WorkspaceAssociationStorageInterface extends ContentEntityStorageInterface {
+
+  /**
+   * Triggers clean-up operations after pushing.
+   *
+   * @param \Drupal\workspaces\WorkspaceInterface $workspace
+   *   A workspace entity.
+   */
+  public function postPush(WorkspaceInterface $workspace);
+
+  /**
+   * Retrieves the content revisions tracked by a given workspace.
+   *
+   * @param string $workspace_id
+   *   The ID of the workspace.
+   * @param bool $all_revisions
+   *   (optional) Whether to return all the tracked revisions for each entity or
+   *   just the latest tracked revision. Defaults to FALSE.
+   *
+   * @return array
+   *   Returns a multidimensional array where the first level keys are entity
+   *   type IDs and the values are an array of entity IDs keyed by revision IDs.
+   */
+  public function getTrackedEntities($workspace_id, $all_revisions = FALSE);
+
+  /**
+   * Gets a list of workspace IDs in which an entity is tracked.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   An entity object.
+   *
+   * @return string[]
+   *   An array of workspace IDs where the given entity is tracked, or an empty
+   *   array if it is not tracked anywhere.
+   */
+  public function getEntityTrackingWorkspaceIds(EntityInterface $entity);
+
+}
diff --git a/core/modules/workspaces/src/WorkspaceManager.php b/core/modules/workspaces/src/WorkspaceManager.php
index b53be3613025a3e12416a50da5fea8a57ea35164..5528988a80baa21e71058e55da8c230c43e1c2c8 100644
--- a/core/modules/workspaces/src/WorkspaceManager.php
+++ b/core/modules/workspaces/src/WorkspaceManager.php
@@ -83,13 +83,6 @@ class WorkspaceManager implements WorkspaceManagerInterface {
    */
   protected $classResolver;
 
-  /**
-   * The workspace association service.
-   *
-   * @var \Drupal\workspaces\WorkspaceAssociationInterface
-   */
-  protected $workspaceAssociation;
-
   /**
    * The workspace negotiator service IDs.
    *
@@ -121,12 +114,10 @@ class WorkspaceManager implements WorkspaceManagerInterface {
    *   A logger instance.
    * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
    *   The class resolver.
-   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
-   *   The workspace association service.
    * @param array $negotiator_ids
    *   The workspace negotiator service IDs.
    */
-  public function __construct(RequestStack $request_stack, EntityTypeManagerInterface $entity_type_manager, MemoryCacheInterface $entity_memory_cache, AccountProxyInterface $current_user, StateInterface $state, LoggerInterface $logger, ClassResolverInterface $class_resolver, WorkspaceAssociationInterface $workspace_association, array $negotiator_ids) {
+  public function __construct(RequestStack $request_stack, EntityTypeManagerInterface $entity_type_manager, MemoryCacheInterface $entity_memory_cache, AccountProxyInterface $current_user, StateInterface $state, LoggerInterface $logger, ClassResolverInterface $class_resolver, array $negotiator_ids) {
     $this->requestStack = $request_stack;
     $this->entityTypeManager = $entity_type_manager;
     $this->entityMemoryCache = $entity_memory_cache;
@@ -134,7 +125,6 @@ public function __construct(RequestStack $request_stack, EntityTypeManagerInterf
     $this->state = $state;
     $this->logger = $logger;
     $this->classResolver = $class_resolver;
-    $this->workspaceAssociation = $workspace_association;
     $this->negotiatorIds = $negotiator_ids;
   }
 
@@ -315,35 +305,67 @@ public function purgeDeletedWorkspacesBatch() {
 
     $batch_size = Settings::get('entity_update_batch_size', 50);
 
+    /** @var \Drupal\workspaces\WorkspaceAssociationStorageInterface $workspace_association_storage */
+    $workspace_association_storage = $this->entityTypeManager->getStorage('workspace_association');
+
     // Get the first deleted workspace from the list and delete the revisions
-    // associated with it, along with the workspace association records.
+    // associated with it, along with the workspace_association entries.
     $workspace_id = reset($deleted_workspace_ids);
-    $tracked_entities = $this->workspaceAssociation->getTrackedEntities($workspace_id);
-
-    $count = 1;
-    foreach ($tracked_entities as $entity_type_id => $entities) {
-      $associated_entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
-      $associated_revisions = $this->workspaceAssociation->getAssociatedRevisions($workspace_id, $entity_type_id);
-      foreach (array_keys($associated_revisions) as $revision_id) {
-        if ($count > $batch_size) {
-          continue 2;
-        }
+    $workspace_association_ids = $this->getWorkspaceAssociationRevisionsToPurge($workspace_id, $batch_size);
 
+    if ($workspace_association_ids) {
+      $workspace_associations = $workspace_association_storage->loadMultipleRevisions(array_keys($workspace_association_ids));
+      foreach ($workspace_associations as $workspace_association) {
+        $associated_entity_storage = $this->entityTypeManager->getStorage($workspace_association->target_entity_type_id->value);
         // Delete the associated entity revision.
-        $associated_entity_storage->deleteRevision($revision_id);
-        $count++;
+        if ($entity = $associated_entity_storage->loadRevision($workspace_association->target_entity_revision_id->value)) {
+          if ($entity->isDefaultRevision()) {
+            $entity->delete();
+          }
+          else {
+            $associated_entity_storage->deleteRevision($workspace_association->target_entity_revision_id->value);
+          }
+        }
+
+        // Delete the workspace_association revision.
+        if ($workspace_association->isDefaultRevision()) {
+          $workspace_association->delete();
+        }
+        else {
+          $workspace_association_storage->deleteRevision($workspace_association->getRevisionId());
+        }
       }
-      // Delete the workspace association entries.
-      $this->workspaceAssociation->deleteAssociations($workspace_id, $entity_type_id, $entities);
     }
 
     // The purging operation above might have taken a long time, so we need to
-    // request a fresh list of tracked entities. If it is empty, we can go ahead
-    // and remove the deleted workspace ID entry from state.
-    if (!$this->workspaceAssociation->getTrackedEntities($workspace_id)) {
+    // request a fresh list of workspace association IDs. If it is empty, we can
+    // go ahead and remove the deleted workspace ID entry from state.
+    if (!$this->getWorkspaceAssociationRevisionsToPurge($workspace_id, $batch_size)) {
       unset($deleted_workspace_ids[$workspace_id]);
       $this->state->set('workspace.deleted', $deleted_workspace_ids);
     }
   }
 
+  /**
+   * Gets a list of workspace association IDs to purge.
+   *
+   * @param string $workspace_id
+   *   The ID of the workspace.
+   * @param int $batch_size
+   *   The maximum number of records that will be purged.
+   *
+   * @return array
+   *   An array of workspace association IDs, keyed by their revision IDs.
+   */
+  protected function getWorkspaceAssociationRevisionsToPurge($workspace_id, $batch_size) {
+    return $this->entityTypeManager->getStorage('workspace_association')
+      ->getQuery()
+      ->allRevisions()
+      ->accessCheck(FALSE)
+      ->condition('workspace', $workspace_id)
+      ->sort('revision_id', 'ASC')
+      ->range(0, $batch_size)
+      ->execute();
+  }
+
 }
diff --git a/core/modules/workspaces/src/WorkspaceOperationFactory.php b/core/modules/workspaces/src/WorkspaceOperationFactory.php
index 7b761a4a3994c6f33a6c014b9312a7c72432b959..d523365667ac508bab102a48d0860ad6d15f7bd4 100644
--- a/core/modules/workspaces/src/WorkspaceOperationFactory.php
+++ b/core/modules/workspaces/src/WorkspaceOperationFactory.php
@@ -36,13 +36,6 @@ class WorkspaceOperationFactory {
    */
   protected $workspaceManager;
 
-  /**
-   * The workspace association service.
-   *
-   * @var \Drupal\workspaces\WorkspaceAssociationInterface
-   */
-  protected $workspaceAssociation;
-
   /**
    * Constructs a new WorkspacePublisher.
    *
@@ -50,16 +43,11 @@ class WorkspaceOperationFactory {
    *   The entity type manager.
    * @param \Drupal\Core\Database\Connection $database
    *   Database connection.
-   * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
-   *   The workspace manager service.
-   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
-   *   The workspace association service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager) {
     $this->entityTypeManager = $entity_type_manager;
     $this->database = $database;
     $this->workspaceManager = $workspace_manager;
-    $this->workspaceAssociation = $workspace_association;
   }
 
   /**
@@ -72,7 +60,7 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Con
    *   A workspace publisher object.
    */
   public function getPublisher(WorkspaceInterface $source) {
-    return new WorkspacePublisher($this->entityTypeManager, $this->database, $this->workspaceManager, $this->workspaceAssociation, $source);
+    return new WorkspacePublisher($this->entityTypeManager, $this->database, $this->workspaceManager, $source);
   }
 
 }
diff --git a/core/modules/workspaces/src/WorkspacePublisher.php b/core/modules/workspaces/src/WorkspacePublisher.php
index d38e97383c39be78a01a655ca638260fe81cf987..c7da6b8be782c14ba48409cbad592f58a61eb244 100644
--- a/core/modules/workspaces/src/WorkspacePublisher.php
+++ b/core/modules/workspaces/src/WorkspacePublisher.php
@@ -37,18 +37,18 @@ class WorkspacePublisher implements WorkspacePublisherInterface {
   protected $database;
 
   /**
-   * The workspace manager.
+   * The workspace association storage.
    *
-   * @var \Drupal\workspaces\WorkspaceManagerInterface
+   * @var \Drupal\workspaces\WorkspaceAssociationStorageInterface
    */
-  protected $workspaceManager;
+  protected $workspaceAssociationStorage;
 
   /**
-   * The workspace association service.
+   * The workspace manager.
    *
-   * @var \Drupal\workspaces\WorkspaceAssociationInterface
+   * @var \Drupal\workspaces\WorkspaceManagerInterface
    */
-  protected $workspaceAssociation;
+  protected $workspaceManager;
 
   /**
    * Constructs a new WorkspacePublisher.
@@ -59,14 +59,12 @@ class WorkspacePublisher implements WorkspacePublisherInterface {
    *   Database connection.
    * @param \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager
    *   The workspace manager.
-   * @param \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association
-   *   The workspace association service.
    */
-  public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceAssociationInterface $workspace_association, WorkspaceInterface $source) {
+  public function __construct(EntityTypeManagerInterface $entity_type_manager, Connection $database, WorkspaceManagerInterface $workspace_manager, WorkspaceInterface $source) {
     $this->entityTypeManager = $entity_type_manager;
     $this->database = $database;
+    $this->workspaceAssociationStorage = $entity_type_manager->getStorage('workspace_association');
     $this->workspaceManager = $workspace_manager;
-    $this->workspaceAssociation = $workspace_association;
     $this->sourceWorkspace = $source;
   }
 
@@ -97,11 +95,6 @@ public function publish() {
             // revisions.
             $entity->setSyncing(TRUE);
             $entity->isDefaultRevision(TRUE);
-
-            // The default revision is not workspace-specific anymore.
-            $field_name = $entity->getEntityType()->getRevisionMetadataKey('workspace');
-            $entity->{$field_name}->target_id = NULL;
-
             $entity->original = $default_revisions[$entity->id()];
             $entity->save();
           }
@@ -114,8 +107,9 @@ public function publish() {
       throw $e;
     }
 
-    // Notify the workspace association that a workspace has been published.
-    $this->workspaceAssociation->postPublish($this->sourceWorkspace);
+    // Notify the workspace association storage that a workspace has been
+    // pushed.
+    $this->workspaceAssociationStorage->postPush($this->sourceWorkspace);
   }
 
   /**
@@ -147,7 +141,7 @@ public function checkConflictsOnTarget() {
   public function getDifferringRevisionIdsOnTarget() {
     $target_revision_difference = [];
 
-    $tracked_entities = $this->workspaceAssociation->getTrackedEntities($this->sourceWorkspace->id());
+    $tracked_entities = $this->workspaceAssociationStorage->getTrackedEntities($this->sourceWorkspace->id());
     foreach ($tracked_entities as $entity_type_id => $tracked_revisions) {
       $entity_type = $this->entityTypeManager->getDefinition($entity_type_id);
 
@@ -177,7 +171,7 @@ public function getDifferringRevisionIdsOnTarget() {
    */
   public function getDifferringRevisionIdsOnSource() {
     // Get the Workspace association revisions which haven't been pushed yet.
-    return $this->workspaceAssociation->getTrackedEntities($this->sourceWorkspace->id());
+    return $this->workspaceAssociationStorage->getTrackedEntities($this->sourceWorkspace->id());
   }
 
   /**
diff --git a/core/modules/workspaces/tests/fixtures/update/drupal-8.6.0-workspaces_installed.php b/core/modules/workspaces/tests/fixtures/update/drupal-8.6.0-workspaces_installed.php
deleted file mode 100644
index 7e6276abfead76a94a69250aa7db85f9d06582ef..0000000000000000000000000000000000000000
Binary files a/core/modules/workspaces/tests/fixtures/update/drupal-8.6.0-workspaces_installed.php and /dev/null differ
diff --git a/core/modules/workspaces/tests/src/Functional/Update/WorkspacesUpdateTest.php b/core/modules/workspaces/tests/src/Functional/Update/WorkspacesUpdateTest.php
deleted file mode 100644
index 0fffd21e3784cbccac98fc13d5632cc130024aa9..0000000000000000000000000000000000000000
--- a/core/modules/workspaces/tests/src/Functional/Update/WorkspacesUpdateTest.php
+++ /dev/null
@@ -1,105 +0,0 @@
-<?php
-
-namespace Drupal\Tests\workspaces\Functional\Update;
-
-use Drupal\FunctionalTests\Update\UpdatePathTestBase;
-
-/**
- * Tests the upgrade path for the Workspaces module.
- *
- * @group workspaces
- * @group Update
- * @group legacy
- */
-class WorkspacesUpdateTest extends UpdatePathTestBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected static $modules = ['workspaces'];
-
-  /**
-   * {@inheritdoc}
-   */
-  public function setDatabaseDumpFiles() {
-    $this->databaseDumpFiles = [
-      __DIR__ . '/../../../../../system/tests/fixtures/update/drupal-8.filled.standard.php.gz',
-      __DIR__ . '/../../../fixtures/update/drupal-8.6.0-workspaces_installed.php',
-    ];
-  }
-
-  /**
-   * Tests the move of workspace association data to a custom table.
-   *
-   * @see workspaces_update_8801()
-   * @see workspaces_post_update_move_association_data()
-   */
-  public function testWorkspaceAssociationRemoval() {
-    $database = \Drupal::database();
-
-    // Check that we have two records in the 'workspace_association' base table
-    // and three records in its revision table.
-    $wa_records = $database->select('workspace_association')->countQuery()->execute()->fetchField();
-    $this->assertEquals(2, $wa_records);
-    $war_records = $database->select('workspace_association_revision')->countQuery()->execute()->fetchField();
-    $this->assertEquals(3, $war_records);
-
-    // Check that the node entity type does not have a 'workspace' field.
-    $this->assertNull(\Drupal::entityDefinitionUpdateManager()->getFieldStorageDefinition('workspace', 'node'));
-
-    $this->runUpdates();
-
-    $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
-
-    // Check that the 'workspace' field has been installed for an entity type
-    // that was workspace-supported before Drupal 8.7.0.
-    $this->assertTrue($entity_definition_update_manager->getFieldStorageDefinition('workspace', 'node'));
-
-    // Check that the 'workspace' field has been installed for an entity type
-    // which became workspace-supported as part of an entity schema update.
-    $this->assertTrue($entity_definition_update_manager->getFieldStorageDefinition('workspace', 'taxonomy_term'));
-
-    // Check that the 'workspace' revision metadata field has been created only
-    // in the revision table.
-    $schema = $database->schema();
-    $this->assertTrue($schema->fieldExists('node_revision', 'workspace'));
-    $this->assertFalse($schema->fieldExists('node', 'workspace'));
-    $this->assertFalse($schema->fieldExists('node_field_data', 'workspace'));
-    $this->assertFalse($schema->fieldExists('node_field_revision', 'workspace'));
-
-    // Check that the 'workspace_association' records have been migrated
-    // properly.
-    $wa_records = $database->select('workspace_association')->fields('workspace_association')->execute()->fetchAll(\PDO::FETCH_ASSOC);
-    $expected = [
-      [
-        'workspace' => 'stage',
-        'target_entity_type_id' => 'node',
-        'target_entity_id' => '1',
-        'target_entity_revision_id' => '2',
-      ],
-      [
-        'workspace' => 'dev',
-        'target_entity_type_id' => 'node',
-        'target_entity_id' => '8',
-        'target_entity_revision_id' => '10',
-      ],
-    ];
-    $this->assertEquals($expected, $wa_records);
-
-    // Check that the 'workspace_association' revisions has been migrated
-    // properly to the new 'workspace' revision metadata field.
-    $revisions = \Drupal::entityTypeManager()->getStorage('node')->loadMultipleRevisions([2, 9, 10]);
-    $this->assertEquals('stage', $revisions[2]->workspace->target_id);
-    $this->assertEquals('dev', $revisions[9]->workspace->target_id);
-    $this->assertEquals('dev', $revisions[10]->workspace->target_id);
-
-    // Check that the 'workspace_association' entity type has been uninstalled.
-    $this->assertNull($entity_definition_update_manager->getEntityType('workspace_association'));
-    $this->assertNull($entity_definition_update_manager->getFieldStorageDefinition('id', 'workspace_association'));
-    $this->assertNull(\Drupal::keyValue('entity.storage_schema.sql')->get('workspace_association.entity_schema_data'));
-
-    // Check that the 'workspace_association_revision' table has been removed.
-    $this->assertFalse($schema->tableExists('workspace_association_revision'));
-  }
-
-}
diff --git a/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php b/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php
index e4932eca3282882270c3f43f311130d27a082dec..e652e3fc826b45a305b34a4e0b9247d5793d75b8 100644
--- a/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php
+++ b/core/modules/workspaces/tests/src/Functional/WorkspacesUninstallTest.php
@@ -36,12 +36,6 @@ public function testUninstallingWorkspace() {
     $this->drupalPostForm(NULL, [], 'Uninstall');
     $session->pageTextContains('The selected modules have been uninstalled.');
     $session->pageTextNotContains('Workspaces');
-
-    $this->assertFalse($this->getDatabaseConnection()->schema()->fieldExists('node_revision', 'workspace'));
-
-    // Verify that the revision metadata key has been removed.
-    $revision_metadata_keys = \Drupal::entityDefinitionUpdateManager()->getEntityType('node')->get('revision_metadata_keys');
-    $this->assertArrayNotHasKey('workspace', $revision_metadata_keys);
   }
 
 }
diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceAccessTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceAccessTest.php
index f8a4964eda303780adc9441df240ca04390ba86a..b8065a15c8dd84def910ac37be9b364737c7c7e2 100644
--- a/core/modules/workspaces/tests/src/Kernel/WorkspaceAccessTest.php
+++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceAccessTest.php
@@ -33,6 +33,7 @@ protected function setUp() {
     $this->installSchema('system', ['sequences']);
 
     $this->installEntitySchema('workspace');
+    $this->installEntitySchema('workspace_association');
     $this->installEntitySchema('user');
 
     // User 1.
diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceCRUDTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceCRUDTest.php
index c8b1705a7e078911b3e27aaac09cf9e5199e7f36..d7d5710c57010e7ad5c58fe21a380a6fb739970a 100644
--- a/core/modules/workspaces/tests/src/Kernel/WorkspaceCRUDTest.php
+++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceCRUDTest.php
@@ -7,6 +7,7 @@
 use Drupal\Tests\node\Traits\NodeCreationTrait;
 use Drupal\Tests\user\Traits\UserCreationTrait;
 use Drupal\workspaces\Entity\Workspace;
+use Drupal\workspaces\Entity\WorkspaceAssociation;
 
 /**
  * Tests CRUD operations for workspaces.
@@ -18,7 +19,6 @@ class WorkspaceCRUDTest extends KernelTestBase {
   use UserCreationTrait;
   use NodeCreationTrait;
   use ContentTypeCreationTrait;
-  use WorkspaceTestTrait;
 
   /**
    * The entity type manager.
@@ -66,7 +66,7 @@ protected function setUp() {
     $this->installSchema('node', ['node_access']);
 
     $this->installEntitySchema('workspace');
-    $this->installSchema('workspaces', ['workspace_association']);
+    $this->installEntitySchema('workspace_association');
     $this->installEntitySchema('node');
 
     $this->installConfig(['filter', 'node', 'system']);
@@ -91,8 +91,10 @@ public function testDeletingWorkspaces() {
     ]);
     $this->setCurrentUser($admin);
 
-    /** @var \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association */
-    $workspace_association = \Drupal::service('workspaces.association');
+    /** @var \Drupal\workspaces\WorkspaceAssociationStorageInterface $workspace_association_storage */
+    $workspace_association_storage = $this->entityTypeManager->getStorage('workspace_association');
+    /** @var \Drupal\node\NodeStorageInterface $node_storage */
+    $node_storage = $this->entityTypeManager->getStorage('node');
 
     // Create a workspace with a very small number of associated node revisions.
     $workspace_1 = Workspace::create([
@@ -104,12 +106,6 @@ public function testDeletingWorkspaces() {
 
     $workspace_1_node_1 = $this->createNode(['status' => FALSE]);
     $workspace_1_node_2 = $this->createNode(['status' => FALSE]);
-
-    // The 'live' workspace should have 2 revisions now. The initial revision
-    // for each node.
-    $live_revisions = $this->getUnassociatedRevisions('node');
-    $this->assertCount(2, $live_revisions);
-
     for ($i = 0; $i < 4; $i++) {
       $workspace_1_node_1->setNewRevision(TRUE);
       $workspace_1_node_1->save();
@@ -118,17 +114,9 @@ public function testDeletingWorkspaces() {
       $workspace_1_node_2->save();
     }
 
-    // The workspace should now track 2 nodes.
-    $tracked_entities = $workspace_association->getTrackedEntities($workspace_1->id());
-    $this->assertCount(2, $tracked_entities['node']);
-
-    // There should still be 2 revisions associated with 'live'.
-    $live_revisions = $this->getUnassociatedRevisions('node');
-    $this->assertCount(2, $live_revisions);
-
-    // The other 8 revisions should be associated with 'workspace_1'.
-    $associated_revisions = $workspace_association->getAssociatedRevisions($workspace_1->id(), 'node');
-    $this->assertCount(8, $associated_revisions);
+    // The workspace should have 10 associated node revisions, 5 for each node.
+    $associated_revisions = $workspace_association_storage->getTrackedEntities($workspace_1->id(), TRUE);
+    $this->assertCount(10, $associated_revisions['node']);
 
     // Check that we are allowed to delete the workspace.
     $this->assertTrue($workspace_1->access('delete', $admin));
@@ -137,17 +125,14 @@ public function testDeletingWorkspaces() {
     // entities and all the node revisions have been deleted as well.
     $workspace_1->delete();
 
-    // There are no more tracked entities in 'workspace_1'.
-    $tracked_entities = $workspace_association->getTrackedEntities($workspace_1->id());
-    $this->assertEmpty($tracked_entities);
-
-    // There are no more revisions associated with 'workspace_1'.
-    $associated_revisions = $workspace_association->getAssociatedRevisions($workspace_1->id(), 'node');
+    $associated_revisions = $workspace_association_storage->getTrackedEntities($workspace_1->id(), TRUE);
     $this->assertCount(0, $associated_revisions);
-
-    // There should still be 2 revisions associated with 'live'.
-    $live_revisions = $this->getUnassociatedRevisions('node');
-    $this->assertCount(2, $live_revisions);
+    $node_revision_count = $node_storage
+      ->getQuery()
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals(0, $node_revision_count);
 
     // Create another workspace, this time with a larger number of associated
     // node revisions so we can test the batch purge process.
@@ -164,27 +149,16 @@ public function testDeletingWorkspaces() {
       $workspace_2_node_1->save();
     }
 
-    // Now there is one entity tracked in 'workspace_2'.
-    $tracked_entities = $workspace_association->getTrackedEntities($workspace_2->id());
-    $this->assertCount(1, $tracked_entities['node']);
-
-    // One revision of this entity is in 'live'.
-    $live_revisions = $this->getUnassociatedRevisions('node', [$workspace_2_node_1->id()]);
-    $this->assertCount(1, $live_revisions);
+    // The workspace should have 60 associated node revisions.
+    $associated_revisions = $workspace_association_storage->getTrackedEntities($workspace_2->id(), TRUE);
+    $this->assertCount(60, $associated_revisions['node']);
 
-    // The other 59 are associated with 'workspace_2'.
-    $associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
-    $this->assertCount(59, $associated_revisions);
-
-    // Delete the workspace and check that we still have 9 revision left to
+    // Delete the workspace and check that we still have 10 revision left to
     // delete.
     $workspace_2->delete();
-    $associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
-    $this->assertCount(9, $associated_revisions);
 
-    // The live revision is also still there.
-    $live_revisions = $this->getUnassociatedRevisions('node', [$workspace_2_node_1->id()]);
-    $this->assertCount(1, $live_revisions);
+    $associated_revisions = $workspace_association_storage->getTrackedEntities($workspace_2->id(), TRUE);
+    $this->assertCount(10, $associated_revisions['node']);
 
     $workspace_deleted = \Drupal::state()->get('workspace.deleted');
     $this->assertCount(1, $workspace_deleted);
@@ -203,94 +177,41 @@ public function testDeletingWorkspaces() {
     // from the "workspace.delete" state entry.
     \Drupal::service('cron')->run();
 
-    $associated_revisions = $workspace_association->getTrackedEntities($workspace_2->id());
-    $this->assertCount(0, $associated_revisions);
-
-    // 'workspace_2 'is empty now.
-    $associated_revisions = $workspace_association->getAssociatedRevisions($workspace_2->id(), 'node', [$workspace_2_node_1->id()]);
+    $associated_revisions = $workspace_association_storage->getTrackedEntities($workspace_2->id(), TRUE);
     $this->assertCount(0, $associated_revisions);
-    $tracked_entities = $workspace_association->getTrackedEntities($workspace_2->id());
-    $this->assertEmpty($tracked_entities);
-
-    // The 3 revisions in 'live' remain.
-    $live_revisions = $this->getUnassociatedRevisions('node');
-    $this->assertCount(3, $live_revisions);
+    $node_revision_count = $node_storage
+      ->getQuery()
+      ->allRevisions()
+      ->count()
+      ->execute();
+    $this->assertEquals(0, $node_revision_count);
 
     $workspace_deleted = \Drupal::state()->get('workspace.deleted');
     $this->assertCount(0, $workspace_deleted);
   }
 
   /**
-   * Tests that deleting a workspace keeps its already published content.
+   * Tests workspace association validation.
+   *
+   * @covers \Drupal\workspaces\Entity\WorkspaceAssociation::validate
    */
-  public function testDeletingPublishedWorkspace() {
-    $admin = $this->createUser([
-      'administer nodes',
-      'create workspace',
-      'view any workspace',
-      'delete any workspace',
-    ]);
-    $this->setCurrentUser($admin);
-
-    $live_workspace = Workspace::create([
-      'id' => 'live',
-      'label' => 'Live',
-    ]);
-    $live_workspace->save();
+  public function testWorkspaceAssociationValidation() {
     $workspace = Workspace::create([
-      'id' => 'stage',
-      'label' => 'Stage',
+      'id' => 'gibbon',
+      'label' => 'Gibbon',
     ]);
     $workspace->save();
-    $this->workspaceManager->setActiveWorkspace($workspace);
-
-    // Create a new node in the 'stage' workspace
-    $node = $this->createNode(['status' => TRUE]);
-
-    // Create an additional workspace-specific revision for the node.
-    $node->setNewRevision(TRUE);
-    $node->save();
-
-    // The node should have 3 revisions now: a default and 2 pending ones.
-    $revisions = $this->entityTypeManager->getStorage('node')->loadMultipleRevisions([1, 2, 3]);
-    $this->assertCount(3, $revisions);
-    $this->assertTrue($revisions[1]->isDefaultRevision());
-    $this->assertFalse($revisions[2]->isDefaultRevision());
-    $this->assertFalse($revisions[3]->isDefaultRevision());
-
-    // Publish the workspace, which should mark revision 3 as the default one
-    // and keep revision 2 as a 'source' draft revision.
-    $workspace->publish();
-    $revisions = $this->entityTypeManager->getStorage('node')->loadMultipleRevisions([1, 2, 3]);
-    $this->assertFalse($revisions[1]->isDefaultRevision());
-    $this->assertFalse($revisions[2]->isDefaultRevision());
-    $this->assertTrue($revisions[3]->isDefaultRevision());
-
-    // Create two new workspace-revisions for the node.
-    $node->setNewRevision(TRUE);
-    $node->save();
-    $node->setNewRevision(TRUE);
-    $node->save();
-
-    // The node should now have 5 revisions.
-    $revisions = $this->entityTypeManager->getStorage('node')->loadMultipleRevisions([1, 2, 3, 4, 5]);
-    $this->assertFalse($revisions[1]->isDefaultRevision());
-    $this->assertFalse($revisions[2]->isDefaultRevision());
-    $this->assertTrue($revisions[3]->isDefaultRevision());
-    $this->assertFalse($revisions[4]->isDefaultRevision());
-    $this->assertFalse($revisions[5]->isDefaultRevision());
-
-    // Delete the workspace and check that only the two new pending revisions
-    // were deleted by the workspace purging process.
-    $workspace->delete();
-
-    $revisions = $this->entityTypeManager->getStorage('node')->loadMultipleRevisions([1, 2, 3, 4, 5]);
-    $this->assertCount(3, $revisions);
-    $this->assertFalse($revisions[1]->isDefaultRevision());
-    $this->assertFalse($revisions[2]->isDefaultRevision());
-    $this->assertTrue($revisions[3]->isDefaultRevision());
-    $this->assertFalse(isset($revisions[4]));
-    $this->assertFalse(isset($revisions[5]));
+    $node = $this->createNode();
+
+    $workspace_association = WorkspaceAssociation::create([
+      'workspace' => $workspace,
+      'target_entity_type_id' => $node->getEntityTypeId(),
+      'target_entity_id' => $node->id(),
+      'target_entity_revision_id' => $node->getRevisionId(),
+    ]);
+
+    $violations = $workspace_association->validate();
+    $this->assertCount(0, $violations);
   }
 
 }
diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
index 1530f3865830743097c2c761d203c4c3d3f68c8b..20a7efd04e30adc75d0cec4cf401851461c09d22 100644
--- a/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
+++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceIntegrationTest.php
@@ -275,7 +275,7 @@ public function testWorkspaces() {
       ],
     ]);
     $test_scenarios['add_published_node_in_stage'] = $revision_state;
-    $expected_workspace_association['add_published_node_in_stage'] = ['stage' => [3, 4, 5, 7]];
+    $expected_workspace_association['add_published_node_in_stage'] = ['stage' => [3, 4, 5, 6, 7]];
 
     // Deploying 'stage' to 'live' should simply make the latest revisions in
     // 'stage' the default ones in 'live'.
@@ -365,9 +365,8 @@ public function testEntityQueryWithoutConditions() {
     $this->switchToWorkspace('stage');
 
     // Add a workspace-specific revision to a pre-existing node.
-    $node = $this->entityTypeManager->getStorage('node')->load(2);
-    $node->title->value = 'stage - 2 - r3 - published';
-    $node->save();
+    $this->nodes[1]->title->value = 'stage - 2 - r3 - published';
+    $this->nodes[1]->save();
 
     $query = $this->entityTypeManager->getStorage('node')->getQuery();
     $query->sort('nid');
@@ -810,7 +809,7 @@ protected function assertEntityQuery(array $expected_values, $entity_type_id) {
   }
 
   /**
-   * Checks the workspace_association records for a test scenario.
+   * Checks the workspace_association entries for a test scenario.
    *
    * @param array $expected
    *   An array of expected values, as defined in ::testWorkspaces().
@@ -818,10 +817,10 @@ protected function assertEntityQuery(array $expected_values, $entity_type_id) {
    *   The ID of the entity type that is being tested.
    */
   protected function assertWorkspaceAssociation(array $expected, $entity_type_id) {
-    /** @var \Drupal\workspaces\WorkspaceAssociationInterface $workspace_association */
-    $workspace_association = \Drupal::service('workspaces.association');
+    /** @var \Drupal\workspaces\WorkspaceAssociationStorageInterface $workspace_association_storage */
+    $workspace_association_storage = $this->entityTypeManager->getStorage('workspace_association');
     foreach ($expected as $workspace_id => $expected_tracked_revision_ids) {
-      $tracked_entities = $workspace_association->getTrackedEntities($workspace_id, $entity_type_id);
+      $tracked_entities = $workspace_association_storage->getTrackedEntities($workspace_id, TRUE);
       $tracked_revision_ids = isset($tracked_entities[$entity_type_id]) ? $tracked_entities[$entity_type_id] : [];
       $this->assertEquals($expected_tracked_revision_ids, array_keys($tracked_revision_ids));
     }
diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceInternalResourceTest.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceInternalResourceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..06201ce7446d31c4275a077b912fa3f7d7ca2e8e
--- /dev/null
+++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceInternalResourceTest.php
@@ -0,0 +1,43 @@
+<?php
+
+namespace Drupal\Tests\workspaces\Kernel;
+
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\rest\Entity\RestResourceConfig;
+use Drupal\rest\RestResourceConfigInterface;
+
+/**
+ * Tests REST module with internal workspace entity types.
+ *
+ * @group workspaces
+ */
+class WorkspaceInternalResourceTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['user', 'serialization', 'rest', 'workspaces'];
+
+  /**
+   * Tests enabling workspace associations for REST throws an exception.
+   *
+   * @see \Drupal\workspaces\Entity\WorkspaceAssociation
+   */
+  public function testCreateWorkspaceAssociationResource() {
+    $this->expectException(PluginNotFoundException::class);
+    $this->expectExceptionMessage('The "entity:workspace_association" plugin does not exist.');
+    RestResourceConfig::create([
+      'id' => 'entity.workspace_association',
+      'granularity' => RestResourceConfigInterface::RESOURCE_GRANULARITY,
+      'configuration' => [
+        'methods' => ['GET'],
+        'formats' => ['json'],
+        'authentication' => ['cookie'],
+      ],
+    ])
+      ->enable()
+      ->save();
+  }
+
+}
diff --git a/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php b/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php
index 50cf4704c396d5961c450169a0eb0fcdaefaf4a7..13cff6a3dfebf3dac95c51b25ef7e5b188ed3cd6 100644
--- a/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php
+++ b/core/modules/workspaces/tests/src/Kernel/WorkspaceTestTrait.php
@@ -35,7 +35,7 @@ protected function initializeWorkspacesModule() {
     $this->workspaceManager = \Drupal::service('workspaces.manager');
 
     $this->installEntitySchema('workspace');
-    $this->installSchema('workspaces', ['workspace_association']);
+    $this->installEntitySchema('workspace_association');
 
     // Create two workspaces by default, 'live' and 'stage'.
     $this->workspaces['live'] = Workspace::create(['id' => 'live']);
@@ -64,33 +64,4 @@ protected function switchToWorkspace($workspace_id) {
     \Drupal::service('workspaces.manager')->setActiveWorkspace($workspace);
   }
 
-  /**
-   * Returns all the revisions which are not associated with any workspace.
-   *
-   * @param string $entity_type_id
-   *   An entity type ID to find revisions for.
-   * @param int[]|string[]|null $entity_ids
-   *   (optional) An array of entity IDs to filter the results by. Defaults to
-   *   NULL.
-   *
-   * @return array
-   *   An array of entity IDs, keyed by revision IDs.
-   */
-  protected function getUnassociatedRevisions($entity_type_id, $entity_ids = NULL) {
-    $entity_type = \Drupal::entityTypeManager()->getDefinition($entity_type_id);
-
-    $query = \Drupal::entityTypeManager()
-      ->getStorage($entity_type_id)
-      ->getQuery()
-      ->allRevisions()
-      ->accessCheck(FALSE)
-      ->notExists($entity_type->get('revision_metadata_keys')['workspace']);
-
-    if ($entity_ids) {
-      $query->condition($entity_type->getKey('id'), $entity_ids, 'IN');
-    }
-
-    return $query->execute();
-  }
-
 }
diff --git a/core/modules/workspaces/workspaces.install b/core/modules/workspaces/workspaces.install
index 2bfc003f0e102871d0d8af9ff9571b4cc9457988..c6ac304b6db36a477bb20594639e99b0cbcdb162 100644
--- a/core/modules/workspaces/workspaces.install
+++ b/core/modules/workspaces/workspaces.install
@@ -5,8 +5,6 @@
  * Contains install, update and uninstall functions for the Workspaces module.
  */
 
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\workspaces\Entity\Workspace;
 
 /**
@@ -34,27 +32,6 @@ function workspaces_requirements($phase) {
   return $requirements;
 }
 
-/**
- * Implements hook_module_preinstall().
- */
-function workspaces_module_preinstall($module) {
-  if ($module !== 'workspaces') {
-    return;
-  }
-
-  /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager */
-  $workspace_manager = \Drupal::service('workspaces.manager');
-  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
-  foreach ($entity_definition_update_manager->getEntityTypes() as $entity_type) {
-    $revision_metadata_keys = $entity_type->get('revision_metadata_keys');
-    if ($workspace_manager->isEntityTypeSupported($entity_type)) {
-      $revision_metadata_keys['workspace'] = 'workspace';
-      $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
-      $entity_definition_update_manager->updateEntityType($entity_type);
-    }
-  }
-}
-
 /**
  * Implements hook_install().
  */
@@ -84,83 +61,3 @@ function workspaces_install() {
     'uid' => $owner_id,
   ])->save();
 }
-
-/**
- * Implements hook_schema().
- */
-function workspaces_schema() {
-  $schema['workspace_association'] = [
-    'description' => 'Stores the association between entity revisions and their workspace.',
-    'fields' => [
-      'workspace' => [
-        'type' => 'varchar_ascii',
-        'length' => 128,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'The workspace ID.',
-      ],
-      'target_entity_type_id' => [
-        'type' => 'varchar_ascii',
-        'length' => EntityTypeInterface::ID_MAX_LENGTH,
-        'not null' => TRUE,
-        'default' => '',
-        'description' => 'The ID of the associated entity type.',
-      ],
-      'target_entity_id' => [
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The ID of the associated entity.',
-      ],
-      'target_entity_revision_id' => [
-        'type' => 'int',
-        'unsigned' => TRUE,
-        'not null' => TRUE,
-        'description' => 'The revision ID of the associated entity.',
-      ],
-    ],
-    'indexes' => [
-      'target_entity_revision_id' => ['target_entity_revision_id'],
-    ],
-    'primary key' => ['workspace', 'target_entity_type_id', 'target_entity_id'],
-  ];
-
-  return $schema;
-}
-
-/**
- * Add the 'workspace' revision metadata field on all supported entity types.
- */
-function workspaces_update_8801() {
-  /** @var \Drupal\workspaces\WorkspaceManagerInterface $workspace_manager */
-  $workspace_manager = \Drupal::service('workspaces.manager');
-  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
-  foreach ($entity_definition_update_manager->getEntityTypes() as $entity_type_id => $entity_type) {
-    if ($workspace_manager->isEntityTypeSupported($entity_type)) {
-      $revision_metadata_keys = $entity_type->get('revision_metadata_keys');
-
-      if (!isset($revision_metadata_keys['workspace'])) {
-        // Bail out if there's an existing field called 'workspace'.
-        if ($entity_definition_update_manager->getFieldStorageDefinition('workspace', $entity_type_id)) {
-          throw new \RuntimeException("An existing 'workspace' field was found for the '$entity_type_id' entity type. Set the 'workspace' revision metadata key to use a different field name and run this update function again.");
-        }
-
-        $revision_metadata_keys['workspace'] = 'workspace';
-        $entity_type->set('revision_metadata_keys', $revision_metadata_keys);
-        $entity_definition_update_manager->updateEntityType($entity_type);
-      }
-
-      $field_storage = BaseFieldDefinition::create('entity_reference')
-        ->setLabel(t('Workspace'))
-        ->setDescription(t('Indicates the workspace that this revision belongs to.'))
-        ->setSetting('target_type', 'workspace')
-        ->setInternal(TRUE)
-        ->setTranslatable(FALSE)
-        ->setRevisionable(TRUE);
-
-      $entity_definition_update_manager->installFieldStorageDefinition($revision_metadata_keys['workspace'], $entity_type_id, 'workspaces', $field_storage);
-    }
-  }
-
-  return t("The 'workspace' revision metadata field has been installed.");
-}
diff --git a/core/modules/workspaces/workspaces.module b/core/modules/workspaces/workspaces.module
index c3b0d0776274589f7b94c4621be88363b90eee45..d47985b223ded51e652cebe5be2d964adc8bbe70 100644
--- a/core/modules/workspaces/workspaces.module
+++ b/core/modules/workspaces/workspaces.module
@@ -8,7 +8,6 @@
 use Drupal\Component\Serialization\Json;
 use Drupal\Core\Entity\EntityFormInterface;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
@@ -67,15 +66,6 @@ function workspaces_field_info_alter(&$definitions) {
     ->fieldInfoAlter($definitions);
 }
 
-/**
- * Implements hook_entity_base_field_info().
- */
-function workspaces_entity_base_field_info(EntityTypeInterface $entity_type) {
-  return \Drupal::service('class_resolver')
-    ->getInstanceFromDefinition(EntityTypeInfo::class)
-    ->entityBaseFieldInfo($entity_type);
-}
-
 /**
  * Implements hook_entity_preload().
  */
diff --git a/core/modules/workspaces/workspaces.post_update.php b/core/modules/workspaces/workspaces.post_update.php
index ac45f3f93285cf1b9b61a7376beab24725123626..0df5add2cb8dde0a926effbd8d899c6e322c3d27 100644
--- a/core/modules/workspaces/workspaces.post_update.php
+++ b/core/modules/workspaces/workspaces.post_update.php
@@ -5,11 +5,6 @@
  * Post update functions for the Workspaces module.
  */
 
-use Drupal\Core\Entity\ContentEntityNullStorage;
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
-use Drupal\Core\Site\Settings;
-
 /**
  * Clear caches due to access changes.
  */
@@ -24,122 +19,3 @@ function workspaces_post_update_remove_default_workspace() {
     $workspace->delete();
   }
 }
-
-/**
- * Move the workspace association data to an entity field and a custom table.
- */
-function workspaces_post_update_move_association_data(&$sandbox) {
-  $database = \Drupal::database();
-  $entity_definition_update_manager = \Drupal::entityDefinitionUpdateManager();
-  $entity_type_manager = \Drupal::entityTypeManager();
-  $entity_type = $entity_definition_update_manager->getEntityType('workspace_association');
-
-  // We can't migrate the workspace association data if the entity type is not
-  // using its default storage.
-  if ($entity_type->getHandlerClasses()['storage'] !== 'Drupal\workspaces\WorkspaceAssociationStorage') {
-    return;
-  }
-
-  // Since the custom storage class doesn't exist anymore, we have to use core's
-  // default storage.
-  $entity_type->setStorageClass(SqlContentEntityStorage::class);
-
-  // If 'progress' is not set, this will be the first run of the batch.
-  if (!isset($sandbox['progress'])) {
-    $sandbox['progress'] = 0;
-    $sandbox['current_id'] = -1;
-
-    // Create a temporary table for the new workspace_association index.
-    $schema = [
-      'description' => 'Stores the association between entity revisions and their workspace.',
-      'fields' => [
-        'workspace' => [
-          'type' => 'varchar_ascii',
-          'length' => 128,
-          'not null' => TRUE,
-          'default' => '',
-          'description' => 'The workspace ID.',
-        ],
-        'target_entity_type_id' => [
-          'type' => 'varchar_ascii',
-          'length' => EntityTypeInterface::ID_MAX_LENGTH,
-          'not null' => TRUE,
-          'default' => '',
-          'description' => 'The ID of the associated entity type.',
-        ],
-        'target_entity_id' => [
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'description' => 'The ID of the associated entity.',
-        ],
-        'target_entity_revision_id' => [
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-          'description' => 'The revision ID of the associated entity.',
-        ],
-      ],
-      'indexes' => [
-        'target_entity_revision_id' => ['target_entity_revision_id'],
-      ],
-      'primary key' => ['workspace', 'target_entity_type_id', 'target_entity_id'],
-    ];
-    if ($database->schema()->tableExists('tmp_workspace_association')) {
-      $database->schema()->dropTable('tmp_workspace_association');
-    }
-    $database->schema()->createTable('tmp_workspace_association', $schema);
-
-    // Copy all the data from the base table of the 'workspace_association'
-    // entity type to the temporary association table.
-    $select = $database->select($entity_type->getBaseTable())
-      ->fields($entity_type->getBaseTable(), ['workspace', 'target_entity_type_id', 'target_entity_id', 'target_entity_revision_id']);
-    $database->insert('tmp_workspace_association')->from($select)->execute();
-  }
-
-  $table_name = $entity_type->getRevisionTable();
-  $revision_field_name = 'revision_id';
-
-  // Get the next entity association revision records to migrate.
-  $step_size = Settings::get('entity_update_batch_size', 50);
-  $workspace_association_records = $database->select($table_name, 't')
-    ->condition("t.$revision_field_name", $sandbox['current_id'], '>')
-    ->fields('t')
-    ->orderBy($revision_field_name, 'ASC')
-    ->range(0, $step_size)
-    ->execute()
-    ->fetchAll();
-
-  foreach ($workspace_association_records as $record) {
-    // Set the workspace reference on the tracked entity revision.
-    /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
-    $revision = $entity_type_manager->getStorage($record->target_entity_type_id)->loadRevision($record->target_entity_revision_id);
-    $revision->set('workspace', $record->workspace);
-    $revision->setSyncing(TRUE);
-    $revision->save();
-
-    $sandbox['progress']++;
-    $sandbox['current_id'] = $record->{$revision_field_name};
-  }
-
-  // Get an updated count of workspace_association revisions that still need to
-  // be migrated to the new storage.
-  $missing = $database->select($table_name, 't')
-    ->condition("t.$revision_field_name", $sandbox['current_id'], '>')
-    ->orderBy($revision_field_name, 'ASC')
-    ->countQuery()
-    ->execute()
-    ->fetchField();
-  $sandbox['#finished'] = $missing ? $sandbox['progress'] / ($sandbox['progress'] + (int) $missing) : 1;
-
-  // Uninstall the 'workspace_association' entity type and rename the temporary
-  // table.
-  if ($sandbox['#finished'] == 1) {
-    $entity_type->setStorageClass(ContentEntityNullStorage::class);
-    $entity_definition_update_manager->uninstallEntityType($entity_type);
-    $database->schema()->dropTable('workspace_association');
-    $database->schema()->dropTable('workspace_association_revision');
-
-    $database->schema()->renameTable('tmp_workspace_association', 'workspace_association');
-  }
-}
diff --git a/core/modules/workspaces/workspaces.services.yml b/core/modules/workspaces/workspaces.services.yml
index 45f1d50746141b382da9faf3884bdcdf826716a1..9823d5ce2ec9125ac961abb408f1f66f8a3ca9fc 100644
--- a/core/modules/workspaces/workspaces.services.yml
+++ b/core/modules/workspaces/workspaces.services.yml
@@ -1,17 +1,12 @@
 services:
   workspaces.manager:
     class: Drupal\workspaces\WorkspaceManager
-    arguments: ['@request_stack', '@entity_type.manager', '@entity.memory_cache', '@current_user', '@state', '@logger.channel.workspaces', '@class_resolver', '@workspaces.association']
+    arguments: ['@request_stack', '@entity_type.manager', '@entity.memory_cache', '@current_user', '@state', '@logger.channel.workspaces', '@class_resolver']
     tags:
       - { name: service_id_collector, tag: workspace_negotiator }
   workspaces.operation_factory:
     class: Drupal\workspaces\WorkspaceOperationFactory
-    arguments: ['@entity_type.manager', '@database', '@workspaces.manager', '@workspaces.association']
-  workspaces.association:
-    class: Drupal\workspaces\WorkspaceAssociation
-    arguments: ['@database', '@entity_type.manager']
-    tags:
-      - { name: backend_overridable }
+    arguments: ['@entity_type.manager', '@database', '@workspaces.manager']
 
   workspaces.negotiator.session:
     class: Drupal\workspaces\Negotiator\SessionWorkspaceNegotiator
@@ -30,12 +25,6 @@ services:
     tags:
       - { name: access_check, applies_to: _has_active_workspace }
 
-  workspaces.entity_schema_listener:
-    class: Drupal\workspaces\EventSubscriber\EntitySchemaSubscriber
-    arguments: ['@entity.definition_update_manager', '@entity.last_installed_schema.repository', '@workspaces.manager']
-    tags:
-      - { name: 'event_subscriber' }
-
   cache_context.workspace:
     class: Drupal\workspaces\WorkspaceCacheContext
     arguments: ['@workspaces.manager']