diff --git a/src/PanelsEvents.php b/src/PanelsEvents.php
new file mode 100644
index 0000000..8bb42e2
--- /dev/null
+++ b/src/PanelsEvents.php
@@ -0,0 +1,23 @@
+<?php
+
+namespace Drupal\panels;
+
+/**
+ * Contains events fired by Panels at various points.
+ */
+final class PanelsEvents {
+
+  /**
+   * The name of the event triggered when a Panels display variant is saved.
+   *
+   * This event allows modules to react to a Panels display variant being saved.
+   * The event listener method receives a \Drupal\panels\PanelsVariantEvent
+   * instance.
+   *
+   * @Event
+   *
+   * @var string
+   */
+  const VARIANT_SAVE = 'panels.variant_save';
+
+}
diff --git a/src/PanelsVariantEvent.php b/src/PanelsVariantEvent.php
new file mode 100644
index 0000000..104f803
--- /dev/null
+++ b/src/PanelsVariantEvent.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\panels;
+
+use Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant;
+use Symfony\Component\EventDispatcher\Event;
+
+/**
+ * Event object for events relating to Panels display variants.
+ */
+class PanelsVariantEvent extends Event {
+
+  /**
+   * The Panels display variant.
+   *
+   * @var \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant
+   */
+  protected $variant;
+
+  /**
+   * PanelsVariantEvent constructor.
+   *
+   * @param \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant $variant
+   *   The Panels display variant.
+   */
+  public function __construct(PanelsDisplayVariant $variant) {
+    $this->variant = $variant;
+  }
+
+  /**
+   * Returns the Panels display variant that triggered the event.
+   *
+   * @return \Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant
+   *   The Panels display variant.
+   */
+  public function getVariant() {
+    return $this->variant;
+  }
+
+}
diff --git a/src/Plugin/PanelsStorage/PageManagerPanelsStorage.php b/src/Plugin/PanelsStorage/PageManagerPanelsStorage.php
index 3e451ef..fcef0cf 100644
--- a/src/Plugin/PanelsStorage/PageManagerPanelsStorage.php
+++ b/src/Plugin/PanelsStorage/PageManagerPanelsStorage.php
@@ -67,6 +67,8 @@ class PageManagerPanelsStorage extends PanelsStorageBase implements ContainerFac
    * {@inheritdoc}
    */
   public function save(PanelsDisplayVariant $panels_display) {
+    parent::save($panels_display);
+
     $id = $panels_display->getStorageId();
     if ($id && ($page_variant = $this->loadPageVariant($id))) {
       $variant_plugin = $page_variant->getVariantPlugin();
diff --git a/src/Storage/PanelsStorageBase.php b/src/Storage/PanelsStorageBase.php
index f52c047..222e3f2 100644
--- a/src/Storage/PanelsStorageBase.php
+++ b/src/Storage/PanelsStorageBase.php
@@ -3,7 +3,50 @@
 namespace Drupal\panels\Storage;
 
 use Drupal\Component\Plugin\PluginBase;
+use Drupal\panels\PanelsEvents;
+use Drupal\panels\PanelsVariantEvent;
+use Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 
+/**
+ * Base class for Panels storage plugins.
+ */
 abstract class PanelsStorageBase extends PluginBase implements PanelsStorageInterface {
 
+  /**
+   * The event dispatcher.
+   *
+   * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
+   */
+  protected $eventDispatcher;
+
+  /**
+   * PanelsStorageBase constructor.
+   *
+   * @param array $configuration
+   *   The plugin configuration.
+   * @param string $plugin_id
+   *   The plugin ID.
+   * @param mixed $plugin_definition
+   *   The plugin definition.
+   * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
+   *   (optional) The event dispatcher.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, EventDispatcherInterface $event_dispatcher = NULL) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    // The event dispatcher is optional here in order to maintain backwards
+    // compatibility.
+    $this->eventDispatcher = $event_dispatcher ?: \Drupal::service('event_dispatcher');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save(PanelsDisplayVariant $panels_display) {
+    // Allow event subscribers to react to the variant being saved.
+    $event = new PanelsVariantEvent($panels_display);
+    $this->eventDispatcher->dispatch(PanelsEvents::VARIANT_SAVE, $event);
+  }
+
 }
