diff --git a/core/modules/content_moderation/content_moderation.services.yml b/core/modules/content_moderation/content_moderation.services.yml
index 5035b67..921a43f 100644
--- a/core/modules/content_moderation/content_moderation.services.yml
+++ b/core/modules/content_moderation/content_moderation.services.yml
@@ -15,8 +15,3 @@ services:
     arguments: ['@content_moderation.moderation_information']
     tags:
       - { name: access_check, applies_to: _content_moderation_latest_version }
-  content_moderation.config_import_subscriber:
-    class: Drupal\content_moderation\EventSubscriber\ConfigImportSubscriber
-    arguments: ['@config.manager', '@entity_type.manager']
-    tags:
-      - { name: event_subscriber }
diff --git a/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowConfigTest.php b/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowConfigTest.php
index 931056e..85984b6 100644
--- a/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowConfigTest.php
+++ b/core/modules/content_moderation/tests/src/Kernel/ContentModerationWorkflowConfigTest.php
@@ -120,7 +120,7 @@ public function testDeletingStateViaConfiguration() {
     catch (ConfigImporterException $e) {
       $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
       $error_log = $this->configImporter->getErrors();
-      $expected = ['The moderation state Test two is being used, but is not in the source storage.'];
+      $expected = ['The state Test two is being used, but is not in the source storage.'];
       $this->assertEqual($expected, $error_log);
     }
 
@@ -135,7 +135,7 @@ public function testDeletingStateViaConfiguration() {
       $this->assertEqual($e->getMessage(), 'There were errors validating the config synchronization.');
       $error_log = $this->configImporter->getErrors();
       $expected = [
-        'The moderation state Test two is being used, but is not in the source storage.',
+        'The state Test two is being used, but is not in the source storage.',
         'The workflow Editorial is being used, and cannot be deleted.',
       ];
       $this->assertEqual($expected, $error_log);
diff --git a/core/modules/content_moderation/src/EventSubscriber/ConfigImportSubscriber.php b/core/modules/workflows/src/EventSubscriber/ConfigImportSubscriber.php
similarity index 93%
rename from core/modules/content_moderation/src/EventSubscriber/ConfigImportSubscriber.php
rename to core/modules/workflows/src/EventSubscriber/ConfigImportSubscriber.php
index 930167f..ee2ade5 100644
--- a/core/modules/content_moderation/src/EventSubscriber/ConfigImportSubscriber.php
+++ b/core/modules/workflows/src/EventSubscriber/ConfigImportSubscriber.php
@@ -1,6 +1,6 @@
 <?php
 
-namespace Drupal\content_moderation\EventSubscriber;
+namespace Drupal\workflows\EventSubscriber;
 
 use Drupal\Core\Config\ConfigImporterEvent;
 use Drupal\Core\Config\ConfigImportValidateEventSubscriberBase;
@@ -9,7 +9,7 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 
 /**
- * Check moderation states are not being used before updating workflow config.
+ * Check workflows and states are not being used before updating configuration.
  */
 class ConfigImportSubscriber extends ConfigImportValidateEventSubscriberBase {
 
@@ -61,7 +61,7 @@ public function onConfigImporterValidate(ConfigImporterEvent $event) {
             foreach (array_keys($diff) as $state_id) {
               $state = $workflow->getTypePlugin()->getState($state_id);
               if ($workflow->getTypePlugin()->workflowStateHasData($workflow, $state)) {
-                $event->getConfigImporter()->logError($this->t('The moderation state @state_label is being used, but is not in the source storage.', ['@state_label' => $state->label()]));
+                $event->getConfigImporter()->logError($this->t('The state @state_label is being used, but is not in the source storage.', ['@state_label' => $state->label()]));
               }
             }
           }
diff --git a/core/modules/workflows/src/Form/WorkflowDeleteForm.php b/core/modules/workflows/src/Form/WorkflowDeleteForm.php
index e122f40..0ae826f 100644
--- a/core/modules/workflows/src/Form/WorkflowDeleteForm.php
+++ b/core/modules/workflows/src/Form/WorkflowDeleteForm.php
@@ -15,7 +15,7 @@ class WorkflowDeleteForm extends EntityConfirmFormBase {
    * {@inheritdoc}
    */
   public function buildForm(array $form, FormStateInterface $form_state) {
-    if ($this->entity->getTypePlugin()->workflowHasData($this->entity)) {
+    if (!$this->entity->access('delete')) {
       $form['#title'] = $this->getQuestion();
       $form['description'] = ['#markup' => $this->t('This workflow is in use. You cannot remove this workflow until you have removed all content using it.')];
       return $form;
diff --git a/core/modules/workflows/src/Form/WorkflowStateDeleteForm.php b/core/modules/workflows/src/Form/WorkflowStateDeleteForm.php
index bfca31e..65b5190 100644
--- a/core/modules/workflows/src/Form/WorkflowStateDeleteForm.php
+++ b/core/modules/workflows/src/Form/WorkflowStateDeleteForm.php
@@ -76,7 +76,7 @@ public function buildForm(array $form, FormStateInterface $form_state, WorkflowI
     $this->workflow = $workflow;
     $this->stateId = $workflow_state;
 
-    if ($this->workflow->getTypePlugin()->workflowStateHasData($this->workflow, $this->workflow->getTypePlugin()->getState($this->stateId))) {
+    if (!$this->workflow->access('delete-state:' . $this->stateId)) {
       $form['#title'] = $this->getQuestion();
       $form['description'] = ['#markup' => $this->t('This workflow state is in use. You cannot remove this workflow state until you have removed all content using it.')];
       return $form;
diff --git a/core/modules/workflows/src/WorkflowAccessControlHandler.php b/core/modules/workflows/src/WorkflowAccessControlHandler.php
index 1e0456c..8cd9cb0 100644
--- a/core/modules/workflows/src/WorkflowAccessControlHandler.php
+++ b/core/modules/workflows/src/WorkflowAccessControlHandler.php
@@ -57,13 +57,17 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter
     if (strpos($operation, 'delete-state') === 0) {
       list(, $state_id) = explode(':', $operation, 2);
       // Deleting a state is editing a workflow, but also we should forbid
-      // access if there is only one state.
-      return AccessResult::allowedIf(count($entity->getTypePlugin()->getStates()) > 1)
+      // access if there is only one state, if the state is a required state or
+      // that state has data associated with it.
+      return AccessResult::allowedIf(count($workflow_type->getStates()) > 1)
         ->andIf(parent::checkAccess($entity, 'edit', $account))
         ->andIf(AccessResult::allowedIf(!in_array($state_id, $workflow_type->getRequiredStates(), TRUE)))
+        ->andIf(AccessResult::allowedIf(!$workflow_type->workflowStateHasData($entity, $workflow_type->getState($state_id))))
         ->addCacheableDependency($entity);
     }
-
+    if ($operation === 'delete' && $workflow_type->workflowHasData($entity)) {
+      return AccessResult::neutral();
+    }
     return parent::checkAccess($entity, $operation, $account);
   }
 
diff --git a/core/modules/workflows/src/WorkflowDeleteAccessCheck.php b/core/modules/workflows/src/WorkflowDeleteAccessCheck.php
deleted file mode 100644
index adbcddd..0000000
--- a/core/modules/workflows/src/WorkflowDeleteAccessCheck.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-
-namespace Drupal\workflows;
-
-use Drupal\Core\Access\AccessResult;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Routing\Access\AccessInterface;
-use Drupal\Core\Routing\RouteMatchInterface;
-use Drupal\Core\Session\AccountInterface;
-use Symfony\Component\Routing\Route;
-
-/**
- * Provides a access checker for deleting a workflow state.
- *
- * @internal
- *   Marked as internal until it's validated this should form part of the public
- *   API in https://www.drupal.org/node/2897148.
- */
-class WorkflowDeleteAccessCheck implements AccessInterface {
-
-  /**
-   * Checks access to deleting a workflow state for a particular route.
-   *
-   * The value of '_workflow_state_delete_access' is ignored. The route must
-   * have the parameters 'workflow' and 'workflow_state'. For example:
-   * @code
-   * pattern: '/foo/{workflow}/bar/{workflow_state}/delete'
-   * requirements:
-   *   _workflow_state_delete_access: 'true'
-   * @endcode
-   * @see \Drupal\Core\ParamConverter\EntityConverter
-   *
-   * @param \Symfony\Component\Routing\Route $route
-   *   The route to check against.
-   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
-   *   The parametrized route
-   * @param \Drupal\Core\Session\AccountInterface $account
-   *   The currently logged in account.
-   *
-   * @return \Drupal\Core\Access\AccessResultInterface
-   *   The access result.
-   */
-  public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account) {
-    // If there is valid entity of the given entity type, check its access.
-    $parameters = $route_match->getParameters();
-    if ($parameters->has('workflow') && $parameters->has('workflow_state')) {
-      $entity = $parameters->get('workflow');
-      if ($entity instanceof EntityInterface) {
-        return $entity->access('delete-state:' . $parameters->get('workflow_state'), $account, TRUE);
-      }
-    }
-    // No opinion, so other access checks should decide if access should be
-    // allowed or not.
-    return AccessResult::neutral();
-  }
-
-}
diff --git a/core/modules/workflows/src/WorkflowTypeInterface.php b/core/modules/workflows/src/WorkflowTypeInterface.php
index 5ef843b..ece2d79 100644
--- a/core/modules/workflows/src/WorkflowTypeInterface.php
+++ b/core/modules/workflows/src/WorkflowTypeInterface.php
@@ -27,25 +27,19 @@ public function label();
   /**
    * Determines if the workflow is being has data associated with it.
    *
-   * @internal
-   *   Marked as internal until it's validated this should form part of the
-   *   public API in https://www.drupal.org/node/2897148.
-   *
    * @param \Drupal\workflows\WorkflowInterface $workflow
    *   The workflow to check.
    *
    * @return bool
    *   TRUE if the workflow is being used, FALSE if not.
+   *
+   * @see \Drupal\workflows\EventSubscriber\ConfigImportSubscriber
    */
   public function workflowHasData(WorkflowInterface $workflow);
 
   /**
    * Determines if the workflow state has data associated with it.
    *
-   * @internal
-   *   Marked as internal until it's validated this should form part of the
-   *   public API in https://www.drupal.org/node/2897148.
-   *
    * @param \Drupal\workflows\WorkflowInterface $workflow
    *   The workflow to check.
    * @param \Drupal\workflows\StateInterface $state
@@ -53,6 +47,8 @@ public function workflowHasData(WorkflowInterface $workflow);
    *
    * @return bool
    *   TRUE if the workflow state is being used, FALSE if not.
+   *
+   * @see \Drupal\workflows\EventSubscriber\ConfigImportSubscriber
    */
   public function workflowStateHasData(WorkflowInterface $workflow, StateInterface $state);
 
diff --git a/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml b/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml
index 1d9e742..c67eac5 100644
--- a/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml
+++ b/core/modules/workflows/tests/modules/workflow_type_test/config/schema/workflow_type_test.schema.yml
@@ -70,3 +70,20 @@ workflow.type_settings.predefined_states_workflow_test_type:
       sequence:
         label: 'Transitions'
         type: workflows.transition
+
+workflow.type_settings.has_data_workflow_type_test:
+  type: mapping
+  label: 'Has data workflow type test'
+  mapping:
+    states:
+      type: sequence
+      label: 'States'
+      sequence:
+        type: workflows.state
+        label: 'States'
+    transitions:
+      type: sequence
+      label: 'Transitions'
+      sequence:
+        label: 'Transitions'
+        type: workflows.transition
diff --git a/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/HasDataTestType.php b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/HasDataTestType.php
new file mode 100644
index 0000000..f9774b4
--- /dev/null
+++ b/core/modules/workflows/tests/modules/workflow_type_test/src/Plugin/WorkflowType/HasDataTestType.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Drupal\workflow_type_test\Plugin\WorkflowType;
+
+use Drupal\workflows\Plugin\WorkflowTypeBase;
+use Drupal\workflows\StateInterface;
+use Drupal\workflows\WorkflowInterface;
+
+/**
+ * Test workflow type.
+ *
+ * @WorkflowType(
+ *   id = "has_data_workflow_type_test",
+ *   label = @Translation("Has Data Workflow Type Test"),
+ * )
+ */
+class HasDataTestType extends WorkflowTypeBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function workflowHasData(WorkflowInterface $workflow) {
+    $workflows_with_data = \Drupal::state()->get('workflows.workflows_with_data');
+    return !empty($workflows_with_data[$workflow->id()]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function workflowStateHasData(WorkflowInterface $workflow, StateInterface $state) {
+    $states_with_data = \Drupal::state()->get('workflows.workflow_states_with_data');
+    return !empty($states_with_data[$workflow->id() . ':' . $state->id()]);
+  }
+
+}
diff --git a/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php b/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
index b15b240..d43958c 100644
--- a/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
+++ b/core/modules/workflows/tests/src/Functional/WorkflowUiTest.php
@@ -70,14 +70,14 @@ public function testAccess() {
     // Ensure that default states can not be deleted.
     \Drupal::state()->set('workflow_type_test.required_states', ['published']);
     $this->drupalGet('admin/config/workflow/workflows/manage/test/state/published/delete');
-    $this->assertSession()->statusCodeEquals(403);
+    $this->assertSession()->buttonNotExists('Delete');
     \Drupal::state()->set('workflow_type_test.required_states', []);
 
     // Delete one of the states and ensure the other test cannot be deleted.
     $this->drupalGet('admin/config/workflow/workflows/manage/test/state/published/delete');
     $this->submitForm([], 'Delete');
     $this->drupalGet('admin/config/workflow/workflows/manage/test/state/draft/delete');
-    $this->assertSession()->statusCodeEquals(403);
+    $this->assertSession()->buttonNotExists('Delete');
   }
 
   /**
diff --git a/core/modules/workflows/tests/src/Kernel/ConfigImportSubscriberTest.php b/core/modules/workflows/tests/src/Kernel/ConfigImportSubscriberTest.php
new file mode 100644
index 0000000..dccaebf
--- /dev/null
+++ b/core/modules/workflows/tests/src/Kernel/ConfigImportSubscriberTest.php
@@ -0,0 +1,143 @@
+<?php
+
+namespace Drupal\Tests\workflows\Kernel;
+
+use Drupal\Core\Config\ConfigImporterException;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\workflows\Entity\Workflow;
+
+/**
+ * @coversDefaultClass \Drupal\workflows\EventSubscriber\ConfigImportSubscriber
+ * @group workflows
+ */
+class ConfigImportSubscriberTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'system',
+    'workflows',
+    'workflow_type_test',
+  ];
+
+  /**
+   * The config storage sync service.
+   *
+   * @var \Drupal\Core\Config\StorageInterface
+   */
+  protected $configStorageSync;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    // Create workflows to use in the test.
+    $this->createTestWorkflow('with_data', 'With Data', [
+      'data' => 'Data',
+      'no_data' => 'No data',
+    ]);
+    $this->createTestWorkflow('without_data', 'Without Data', [
+      'no_data' => 'No data',
+    ]);
+    // The "with_data" workflow and the "data" state will return TRUE for the
+    // associated hasData methods. The rest will not.
+    $this->container->get('state')->set('workflows.workflows_with_data', [
+      'with_data' => TRUE,
+    ]);
+    $this->container->get('state')->set('workflows.workflow_states_with_data', [
+      'with_data:data' => TRUE,
+    ]);
+
+    $this->configStorageSync = $this->container->get('config.storage.sync');
+    $this->copyConfig($this->container->get('config.storage'), $this->container->get('config.storage.sync'));
+  }
+
+  /**
+   * @covers ::onConfigImporterValidate
+   */
+  public function testDeletingStates() {
+    // Removing states without data will succeed, even if the workflow has data.
+    $this->alterConfigData('workflows.workflow.with_data', function(&$data) {
+      unset($data['type_settings']['states']['no_data']);
+    });
+    $this->alterConfigData('workflows.workflow.without_data', function(&$data) {
+      unset($data['type_settings']['states']['no_data']);
+    });
+    $this->configImporter()->reset()->import();
+
+    // Removing a state with data will cause an import exception.
+    $this->alterConfigData('workflows.workflow.with_data', function(&$data) {
+      unset($data['type_settings']['states']['data']);
+    });
+    try {
+      $this->configImporter()->reset()->import();
+      $this->fail();
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEquals(['The state Data is being used, but is not in the source storage.'], $this->configImporter->getErrors());
+    }
+  }
+
+  /**
+   * @covers ::onConfigImporterValidate
+   */
+  public function testDeletingWorkflows() {
+    // Deleting a workflow without data will succeed.
+    $this->configStorageSync->delete('workflows.workflow.without_data');
+    $this->configImporter()->reset()->import();
+
+    // Deleting a workflow with data will cause an import exception.
+    $this->configStorageSync->delete('workflows.workflow.with_data');
+    try {
+      $this->configImporter()->reset()->import();
+    }
+    catch (ConfigImporterException $e) {
+      $this->assertEquals([
+        'The workflow With Data is being used, and cannot be deleted.',
+      ], $this->configImporter->getErrors());
+    }
+  }
+
+  /**
+   * Alter the values of an item of configuration and write to the storage sync.
+   *
+   * @param string $id
+   *   The ID of the configuration object.
+   * @param callable $alter
+   *   The alterations which should be made.
+   */
+  protected function alterConfigData($id, $alter) {
+    $config_data = $this->config($id)->get();
+    $alter($config_data);
+    $this->configStorageSync->write($id, $config_data);
+  }
+
+  /**
+   * Create and save a test workflow of type "has_data_workflow_type_test".
+   *
+   * @param string $id
+   *   The ID.
+   * @param string $label
+   *   The label.
+   * @param array $states
+   *   An array of states.
+   *
+   * @return \Drupal\workflows\WorkflowInterface
+   */
+  protected function createTestWorkflow($id, $label, array $states) {
+    $workflow = Workflow::create([
+      'label' => $label,
+      'id' => $id,
+      'type' => 'has_data_workflow_type_test',
+    ]);
+    foreach ($states as $id => $label) {
+      $workflow->getTypePlugin()->addState($id, $label);
+    }
+    $workflow->save();
+    return $workflow;
+  }
+
+}
diff --git a/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php b/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php
index cd4e7ce..2d97a50 100644
--- a/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php
+++ b/core/modules/workflows/tests/src/Kernel/WorkflowAccessControlHandlerTest.php
@@ -65,6 +65,15 @@ protected function setUp() {
     $this->createUser([]);
     $this->user = $this->createUser([]);
     $this->adminUser = $this->createUser(['administer workflows']);
+
+    // The "with_data" workflow and the "with_data" state will return TRUE for
+    // the associated hasData methods.
+    $this->container->get('state')->set('workflows.workflows_with_data', [
+      'with_data' => TRUE,
+    ]);
+    $this->container->get('state')->set('workflows.workflow_states_with_data', [
+      'with_data:with_data' => TRUE,
+    ]);
   }
 
   /**
@@ -102,10 +111,10 @@ public function testCheckCreateAccess() {
    * @covers ::checkAccess
    * @dataProvider checkAccessProvider
    */
-  public function testCheckAccess($user, $operation, $result, $states_to_create = []) {
+  public function testCheckAccess($workflow_id, $user, $operation, $result, $states_to_create = []) {
     $workflow = Workflow::create([
-      'type' => 'workflow_type_test',
-      'id' => 'test_workflow',
+      'type' => 'has_data_workflow_type_test',
+      'id' => $workflow_id,
     ]);
     $workflow->save();
     $workflow_type = $workflow->getTypePlugin();
@@ -131,27 +140,32 @@ public function checkAccessProvider() {
 
     return [
       'Admin view' => [
+        'test_workflow',
         'adminUser',
         'view',
         AccessResult::allowed()->addCacheContexts(['user.permissions']),
       ],
       'Admin update' => [
+        'test_workflow',
         'adminUser',
         'update',
         AccessResult::allowed()->addCacheContexts(['user.permissions']),
       ],
       'Admin delete' => [
+        'test_workflow',
         'adminUser',
         'delete',
         AccessResult::allowed()->addCacheContexts(['user.permissions']),
       ],
       'Admin delete only state' => [
+        'test_workflow',
         'adminUser',
         'delete-state:foo',
         AccessResult::neutral()->addCacheTags(['config:workflows.workflow.test_workflow']),
         ['foo' => FALSE],
       ],
       'Admin delete one of two states' => [
+        'test_workflow',
         'adminUser',
         'delete-state:foo',
         AccessResult::allowed()
@@ -160,6 +174,7 @@ public function checkAccessProvider() {
         ['foo' => FALSE, 'bar' => FALSE],
       ],
       'Admin delete required state when there are >1 states' => [
+        'test_workflow',
         'adminUser',
         'delete-state:foo',
         AccessResult::allowed()
@@ -168,6 +183,7 @@ public function checkAccessProvider() {
         ['foo' => TRUE, 'bar' => FALSE],
       ],
       'User view' => [
+        'test_workflow',
         'user',
         'view',
         AccessResult::neutral()
@@ -175,6 +191,7 @@ public function checkAccessProvider() {
           ->setReason("The 'administer workflows' permission is required."),
       ],
       'User update' => [
+        'test_workflow',
         'user',
         'update',
         AccessResult::neutral()
@@ -182,6 +199,7 @@ public function checkAccessProvider() {
           ->setReason("The 'administer workflows' permission is required."),
       ],
       'User delete' => [
+        'test_workflow',
         'user',
         'delete',
         AccessResult::neutral()
@@ -189,12 +207,14 @@ public function checkAccessProvider() {
           ->setReason("The 'administer workflows' permission is required."),
       ],
       'User delete only state' => [
+        'test_workflow',
         'user',
         'delete-state:foo',
         AccessResult::neutral()->addCacheTags(['config:workflows.workflow.test_workflow']),
         ['foo' => FALSE],
       ],
       'User delete one of two states' => [
+        'test_workflow',
         'user',
         'delete-state:foo',
         AccessResult::neutral()
@@ -204,6 +224,7 @@ public function checkAccessProvider() {
         ['foo' => FALSE, 'bar' => FALSE],
       ],
       'User delete required state when there are >1 states' => [
+        'test_workflow',
         'user',
         'delete-state:foo',
         AccessResult::neutral()
@@ -212,6 +233,33 @@ public function checkAccessProvider() {
           ->setReason("The 'administer workflows' permission is required."),
         ['foo' => TRUE, 'bar' => FALSE],
       ],
+      'Admin cannot delete state with data' => [
+        'with_data',
+        'adminUser',
+        'delete-state:with_data',
+        AccessResult::neutral()
+          ->addCacheTags(['config:workflows.workflow.with_data'])
+          ->addCacheContexts([]), // @todo, should these be uncacheable?
+        ['with_data' => FALSE],
+      ],
+      'Admin cannot delete workflow with data' => [
+        'with_data',
+        'adminUser',
+        'delete',
+        AccessResult::neutral()
+          ->addCacheTags([])
+          ->addCacheContexts([]), // @todo, should these be uncacheable?
+        ['foo' => FALSE],
+      ],
+      'Admin can update workflow with data' => [
+        'with_data',
+        'adminUser',
+        'update',
+        AccessResult::allowed()
+          ->addCacheTags([])
+          ->addCacheContexts(['user.permissions']), // @todo, should these be uncacheable?
+        ['foo' => FALSE],
+      ],
     ];
   }
 
diff --git a/core/modules/workflows/workflows.routing.yml b/core/modules/workflows/workflows.routing.yml
index 329ed10..3e3cdae 100644
--- a/core/modules/workflows/workflows.routing.yml
+++ b/core/modules/workflows/workflows.routing.yml
@@ -20,7 +20,7 @@ entity.workflow.delete_state_form:
     _form: '\Drupal\workflows\Form\WorkflowStateDeleteForm'
     _title: 'Delete state'
   requirements:
-    _workflow_state_delete_access: 'true'
+    _entity_access: 'workflow.edit'
 
 entity.workflow.add_transition_form:
   path: '/admin/config/workflow/workflows/manage/{workflow}/add_transition'
@@ -45,3 +45,13 @@ entity.workflow.delete_transition_form:
     _title: 'Delete transition'
   requirements:
     _entity_access: 'workflow.edit'
+
+entity.workflow.delete_form:
+  path: '/admin/config/workflow/workflows/manage/{workflow}/delete'
+  defaults:
+    _entity_form: 'workflow.delete'
+    _title_callback: '\Drupal\Core\Entity\Controller\EntityController::deleteTitle'
+  requirements:
+    # Allow users to access the delete form with "edit" permission. The form does
+    # does appropriate access checking internally.
+    _entity_access: 'workflow.edit'
diff --git a/core/modules/workflows/workflows.services.yml b/core/modules/workflows/workflows.services.yml
index 7d32420..4096929 100644
--- a/core/modules/workflows/workflows.services.yml
+++ b/core/modules/workflows/workflows.services.yml
@@ -4,7 +4,8 @@ services:
     parent: default_plugin_manager
     tags:
       - { name: plugin_manager_cache_clear }
-  workflows.access_check.delete_state:
-    class: \Drupal\workflows\WorkflowDeleteAccessCheck
+  workflows.config_import_subscriber:
+    class: Drupal\workflows\EventSubscriber\ConfigImportSubscriber
+    arguments: ['@config.manager', '@entity_type.manager']
     tags:
-      - { name: access_check, applies_to: _workflow_state_delete_access }
+      - { name: event_subscriber }
