diff --git a/core/modules/content_moderation/src/Entity/ContentModerationState.php b/core/modules/content_moderation/src/Entity/ContentModerationState.php
index 5b1c250..eab7924 100644
--- a/core/modules/content_moderation/src/Entity/ContentModerationState.php
+++ b/core/modules/content_moderation/src/Entity/ContentModerationState.php
@@ -3,6 +3,7 @@
 namespace Drupal\content_moderation\Entity;
 
 use Drupal\content_moderation\ContentModerationStateInterface;
+use Drupal\content_moderation\Event\ContentModerationState as ContentModerationStateEvent;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -176,7 +177,15 @@ public function save() {
    *   In case of failures an exception is thrown.
    */
   protected function realSave() {
-    return parent::save();
+    $result = parent::save();
+    $event = new ContentModerationStateEvent($this);
+    if ($result === SAVED_NEW) {
+      \Drupal::service('event_dispatcher')->dispatch(ContentModerationStateEvent::CREATED, $event);
+    }
+    else {
+      \Drupal::service('event_dispatcher')->dispatch(ContentModerationStateEvent::UPDATED, $event);
+    }
+    return $result;
   }
 
 }
diff --git a/core/modules/content_moderation/src/Event/ContentModerationState.php b/core/modules/content_moderation/src/Event/ContentModerationState.php
new file mode 100644
index 0000000..60ffa2c
--- /dev/null
+++ b/core/modules/content_moderation/src/Event/ContentModerationState.php
@@ -0,0 +1,60 @@
+<?php
+
+namespace Drupal\content_moderation\Event;
+
+use Drupal\content_moderation\ContentModerationStateInterface;
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Defines content moderation state change events.
+ *
+ * @see \Drupal\content_moderation\Entity\ContentModerationState
+ */
+class ContentModerationState extends Event {
+
+  /**
+   * Name of the event fired when saving a new moderation state entity.
+   *
+   * @Event
+   *
+   * @var string
+   */
+  const CREATED = 'content_moderation.created';
+
+  /**
+   * Name of the event fired when updating an existing moderation state entity.
+   *
+   * @Event
+   *
+   * @var string
+   */
+  const UPDATED = 'content_moderation.updated';
+
+  /**
+   * The moderation state entity.
+   *
+   * @var \Drupal\content_moderation\ContentModerationStateInterface
+   */
+  protected $moderationState;
+
+  /**
+   * Constructs the content moderation state event.
+   *
+   * @param \Drupal\content_moderation\ContentModerationStateInterface $moderation_state
+   *   The new or updated moderation state entity.
+   */
+  public function __construct(ContentModerationStateInterface $moderation_state) {
+    $this->moderationState = $moderation_state;
+  }
+
+  /**
+   * Retrieve the content moderation state entity related to this event.
+   *
+   * @return \Drupal\content_moderation\ContentModerationStateInterface
+   *   The content moderation state entity.
+   */
+  public function getModerationState() {
+    return $this->moderationState;
+  }
+
+}
diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_event/content_moderation_test_event.info.yml b/core/modules/content_moderation/tests/modules/content_moderation_test_event/content_moderation_test_event.info.yml
new file mode 100644
index 0000000..36b8d17
--- /dev/null
+++ b/core/modules/content_moderation/tests/modules/content_moderation_test_event/content_moderation_test_event.info.yml
@@ -0,0 +1,9 @@
+name: 'Content moderation test event'
+type: module
+description: 'Provides an event subscriber to content moderation entity updates.'
+package: Testing
+version: VERSION
+core: 8.x
+dependencies:
+  - content_moderation
+  - node
diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_event/content_moderation_test_event.services.yml b/core/modules/content_moderation/tests/modules/content_moderation_test_event/content_moderation_test_event.services.yml
new file mode 100644
index 0000000..8b46008
--- /dev/null
+++ b/core/modules/content_moderation/tests/modules/content_moderation_test_event/content_moderation_test_event.services.yml
@@ -0,0 +1,6 @@
+services:
+  content_moderation_test_event.state_subscriber:
+    class: \Drupal\content_moderation_test_event\EventSubscriber\Test
+    arguments: ['@state']
+    tags:
+      - { name: event_subscriber }
diff --git a/core/modules/content_moderation/tests/modules/content_moderation_test_event/src/EventSubscriber/Test.php b/core/modules/content_moderation/tests/modules/content_moderation_test_event/src/EventSubscriber/Test.php
new file mode 100644
index 0000000..2c7ac38
--- /dev/null
+++ b/core/modules/content_moderation/tests/modules/content_moderation_test_event/src/EventSubscriber/Test.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Drupal\content_moderation_test_event\EventSubscriber;
+
+use Drupal\content_moderation\Event\ContentModerationState;
+use Drupal\Core\State\StateInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * React to created and updated content moderation state entities.
+ */
+class Test implements EventSubscriberInterface {
+
+  /**
+   * The state service.
+   *
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * Constructs the event subscriber.
+   *
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state service.
+   */
+  public function __construct(StateInterface $state) {
+    $this->state = $state;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[ContentModerationState::CREATED] = ['onCreate', 50];
+    $events[ContentModerationState::UPDATED] = ['onUpdate', 50];
+
+    return $events;
+  }
+
+  /**
+   * React to newly created content moderation entities.
+   *
+   * @param \Drupal\content_moderation\Event\ContentModerationState $event
+   *   The fired event.
+   */
+  public function onCreate(ContentModerationState $event) {
+    $moderation_state = $event->getModerationState();
+    $this->state->set('content_moderation_test_event.created', $moderation_state->id());
+  }
+
+  /**
+   * React to updated content moderation entities.
+   *
+   * @param \Drupal\content_moderation\Event\ContentModerationState $event
+   *   The fired event.
+   */
+  public function onUpdate(ContentModerationState $event) {
+    $moderation_state = $event->getModerationState();
+    $this->state->set('content_moderation_test_event.updated', $moderation_state->id());
+  }
+
+}
diff --git a/core/modules/content_moderation/tests/src/Kernel/Event/ContentModerationStateTest.php b/core/modules/content_moderation/tests/src/Kernel/Event/ContentModerationStateTest.php
new file mode 100644
index 0000000..333125a
--- /dev/null
+++ b/core/modules/content_moderation/tests/src/Kernel/Event/ContentModerationStateTest.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Drupal\Tests\content_moderation\Kernel\Event;
+
+use Drupal\content_moderation\Entity\ContentModerationState;
+use Drupal\KernelTests\KernelTestBase;
+
+/**
+ * Tests events are properly fired during create/save of moderation states.
+ *
+ * @group content_moderation
+ */
+class ContentModerationStateTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = [
+    'content_moderation',
+    'content_moderation_test_event',
+    'user',
+    'workflows',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $this->installEntitySchema('content_moderation_state');
+    $this->installEntitySchema('user');
+    $this->installConfig('workflows');
+  }
+
+  /**
+   * Tests events for adding and updating moderation state entities.
+   */
+  public function testCreateUpdateStates() {
+    // Utilize the state system to track if the event was fired.
+    $this->assertFalse(\Drupal::state()->get('content_moderation_test_event.created', FALSE));
+    $state = ContentModerationState::create(['workflow' => 'editorial']);
+    ContentModerationState::updateOrCreateFromEntity($state);
+    // @see \Drupal\content_moderation_test_event\EventSubscriber\Test::onCreate
+    $this->assertEquals($state->id(), \Drupal::state()->get('content_moderation_test_event.created', FALSE));
+
+    $this->assertFalse(\Drupal::state()->get('content_moderation_test_event.updated', FALSE));
+    ContentModerationState::updateOrCreateFromEntity($state);
+    // @see \Drupal\content_moderation_test_event\EventSubscriber\Test::onUpdate
+    $this->assertEquals($state->id(), \Drupal::state()->get('content_moderation_test_event.updated', FALSE));
+  }
+
+}
