diff --git a/search_api.plugin_type.yml b/search_api.plugin_type.yml
index c1b49c7..1fbd834 100644
--- a/search_api.plugin_type.yml
+++ b/search_api.plugin_type.yml
@@ -8,6 +8,11 @@ search_api_data_type:
   plugin_manager_service_id: plugin.manager.search_api.data_type
   plugin_definition_decorator_class: \Drupal\plugin\PluginDefinition\ArrayPluginDefinitionDecorator
 
+search_api_display:
+  label: Search API display
+  plugin_manager_service_id: plugin.manager.search_api.display
+  plugin_definition_decorator_class: \Drupal\plugin\PluginDefinition\ArrayPluginDefinitionDecorator
+
 search_api_processor:
   label: Search API processor
   plugin_manager_service_id: plugin.manager.search_api.processor
diff --git a/search_api.services.yml b/search_api.services.yml
index 6c1207a..61db9d4 100644
--- a/search_api.services.yml
+++ b/search_api.services.yml
@@ -18,6 +18,10 @@ services:
     class: Drupal\search_api\Datasource\DatasourcePluginManager
     parent: default_plugin_manager
 
+  plugin.manager.search_api.display:
+    class: Drupal\search_api\Display\DisplayPluginManager
+    parent: default_plugin_manager
+
   plugin.manager.search_api.processor:
     class: Drupal\search_api\Processor\ProcessorPluginManager
     arguments: ['@container.namespaces', '@cache.discovery', '@module_handler', '@string_translation']
diff --git a/src/Annotation/SearchApiDisplay.php b/src/Annotation/SearchApiDisplay.php
new file mode 100644
index 0000000..0553ae5
--- /dev/null
+++ b/src/Annotation/SearchApiDisplay.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Drupal\search_api\Annotation;
+
+use Drupal\Component\Annotation\Plugin;
+
+/**
+ * Defines a Search API display annotation object.
+ *
+ * @see \Drupal\search_api\Display\DisplayPluginManager
+ * @see \Drupal\search_api\Display\DisplayInterface
+ * @see \Drupal\search_api\Display\DisplayPluginBase
+ * @see plugin_api
+ *
+ * @Annotation
+ */
+class SearchApiDisplay extends Plugin {
+
+  /**
+   * The display plugin ID.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The human-readable name of the display plugin.
+   *
+   * @ingroup plugin_translatable
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $label;
+
+  /**
+   * The human-readable description for the display plugin.
+   *
+   * @ingroup plugin_translatable
+   *
+   * @var \Drupal\Core\Annotation\Translation
+   */
+  public $description;
+
+}
diff --git a/src/Display/DisplayDeriverBase.php b/src/Display/DisplayDeriverBase.php
new file mode 100644
index 0000000..1b9828d
--- /dev/null
+++ b/src/Display/DisplayDeriverBase.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Drupal\search_api\Display;
+
+use Drupal\Core\Entity\EntityTypeManager;
+use Drupal\Core\Plugin\Discovery\ContainerDeriverInterface;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * A base class for display derivers.
+ */
+abstract class DisplayDeriverBase implements ContainerDeriverInterface {
+
+  use StringTranslationTrait;
+
+  /**
+   * List of derivative definitions.
+   *
+   * @var array
+   */
+  protected $derivatives = array();
+
+  /**
+   * The entity manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManager
+   */
+  protected $entityTypeManager;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, $base_plugin_id) {
+    $deriver = new static();
+
+    $entity_type_manager = $container->get('entity_type.manager');
+    $deriver->setEntityTypeManager($entity_type_manager);
+
+    $translation = $container->get('string_translation');
+    $deriver->setStringTranslation($translation);
+
+    return $deriver;
+  }
+
+  /**
+   * Retrieves the entity manager.
+   *
+   * @return \Drupal\Core\Entity\EntityTypeManager
+   *   The entity manager.
+   */
+  public function getEntityTypeManager() {
+    return $this->entityTypeManager;
+  }
+
+  /**
+   * Sets the entity manager.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManager $entity_type_manager
+   *   The entity manager.
+   *
+   * @return $this
+   */
+  public function setEntityTypeManager(EntityTypeManager $entity_type_manager) {
+    $this->entityTypeManager = $entity_type_manager;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinition($derivative_id, $base_plugin_definition) {
+    $derivatives = $this->getDerivativeDefinitions($base_plugin_definition);
+    return isset($derivatives[$derivative_id]) ? $derivatives[$derivative_id] : NULL;
+  }
+
+  /**
+   * Compares two plugin definitions according to their labels.
+   *
+   * @param array $a
+   *   A plugin definition, with at least a "label" key.
+   * @param array $b
+   *   Another plugin definition.
+   *
+   * @return int
+   *   An integer less than, equal to, or greater than zero if the first
+   *   argument is considered to be respectively less than, equal to, or greater
+   *   than the second.
+   */
+  public function compareDerivatives(array $a, array $b) {
+    return strnatcasecmp($a['label'], $b['label']);
+  }
+
+}
diff --git a/src/Display/DisplayInterface.php b/src/Display/DisplayInterface.php
new file mode 100644
index 0000000..f5a0f24
--- /dev/null
+++ b/src/Display/DisplayInterface.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace Drupal\search_api\Display;
+
+use Drupal\Component\Plugin\DerivativeInspectionInterface;
+use Drupal\Component\Plugin\PluginInspectionInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+
+/**
+ * Defines an interface for display plugins.
+ *
+ * @see \Drupal\search_api\Annotation\SearchApiDisplay
+ * @see \Drupal\search_api\Display\DisplayPluginManager
+ * @see \Drupal\search_api\Display\DisplayPluginBase
+ * @see plugin_api
+ */
+interface DisplayInterface extends PluginInspectionInterface, DerivativeInspectionInterface, ContainerFactoryPluginInterface {
+
+  /**
+   * Returns the display label.
+   *
+   * @return string
+   *   A human-readable label for the display.
+   */
+  public function label();
+
+  /**
+   * Returns the display description.
+   *
+   * @return string
+   *   A human-readable description for the display.
+   */
+  public function getDescription();
+
+  /**
+   * Returns the index used by this display.
+   *
+   * @return \Drupal\search_api\IndexInterface
+   *   The search index used by this display.
+   */
+  public function getIndex();
+
+  /**
+   * Returns the path used for this display.
+   *
+   * @return \Drupal\Core\Url
+   *   The path of the display.
+   */
+  public function getPath();
+
+  /**
+   * Returns true if the display is being rendered in the current request.
+   *
+   * @return bool
+   *   True when the display is rendered in the current request.
+   */
+  public function isRenderedInCurrentRequest();
+
+}
diff --git a/src/Display/DisplayPluginBase.php b/src/Display/DisplayPluginBase.php
new file mode 100644
index 0000000..d4c1a72
--- /dev/null
+++ b/src/Display/DisplayPluginBase.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Drupal\search_api\Display;
+
+use Drupal\Core\Path\CurrentPathStack;
+use Drupal\Core\Plugin\PluginBase;
+use Drupal\Core\Url;
+use Drupal\search_api\Entity\Index;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines a base class from which other display classes may extend.
+ *
+ * Plugins extending this class need to define a plugin definition array through
+ * annotation. The definition includes the following keys:
+ * - id: The unique, system-wide identifier of the display class.
+ * - label: Human-readable name of the display class, translated.
+ *
+ * A complete plugin definition should be written as in this example:
+ *
+ * @code
+ * @SearchApiDisplay(
+ *   id = "my_display",
+ *   label = @Translation("My display"),
+ *   description = @Translation("A few words about this search display"),
+ * )
+ * @endcode
+ *
+ * @see \Drupal\search_api\Annotation\SearchApiDisplay
+ * @see \Drupal\search_api\Display\DisplayPluginManager
+ * @see \Drupal\search_api\Display\DisplayInterface
+ * @see plugin_api
+ */
+abstract class DisplayPluginBase extends PluginBase implements DisplayInterface {
+
+  /**
+   * The current path service.
+   *
+   * @var CurrentPathStack|null
+   */
+  protected $currentPath;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    $display = new static($configuration, $plugin_id, $plugin_definition);
+
+    $display->setCurrentPath($container->get('path.current'));
+
+    return $display;
+  }
+
+  /**
+   * Retrieves the current path service.
+   *
+   * @return CurrentPathStack
+   *   The current path service.
+   */
+  public function getCurrentPath() {
+    return $this->currentPath ?: \Drupal::service('path.current');
+  }
+
+  /**
+   * Sets the current path service.
+   *
+   * @param \Drupal\Core\Path\CurrentPathStack $current_path
+   *   The new current path service.
+   *
+   * @return $this
+   */
+  public function setCurrentPath(CurrentPathStack $current_path) {
+    $this->currentPath = $current_path;
+    return $this;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function label() {
+    $plugin_definition = $this->getPluginDefinition();
+    return $plugin_definition['label'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDescription() {
+    $plugin_definition = $this->getPluginDefinition();
+    return $plugin_definition['description'];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getIndex() {
+    $plugin_definition = $this->getPluginDefinition();
+    return Index::load($plugin_definition['index']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPath() {
+    $plugin_definition = $this->getPluginDefinition();
+    return Url::fromUserInput($plugin_definition['path']);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function isRenderedInCurrentRequest() {
+    $plugin_definition = $this->getPluginDefinition();
+    if (isset($plugin_definition['path'])) {
+      $current_path = $this->getCurrentPath()->getPath();
+      return $current_path == $plugin_definition['path'];
+    }
+    return FALSE;
+  }
+
+}
diff --git a/src/Display/DisplayPluginManager.php b/src/Display/DisplayPluginManager.php
new file mode 100644
index 0000000..ff7739e
--- /dev/null
+++ b/src/Display/DisplayPluginManager.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\search_api\Display;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+
+/**
+ * Manages display plugins.
+ *
+ * @see \Drupal\search_api\Annotation\SearchApiDisplay
+ * @see \Drupal\search_api\Display\DisplayInterface
+ * @see \Drupal\search_api\Display\DisplayPluginBase
+ * @see plugin_api
+ */
+class DisplayPluginManager extends DefaultPluginManager {
+
+  /**
+   * Static cache for the display definitions.
+   *
+   * @var string[][]
+   *
+   * @see \Drupal\search_api\Display\DisplayPluginManager::getInstances()
+   */
+  protected $displays = NULL;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
+    parent::__construct('Plugin/search_api/display', $namespaces, $module_handler, 'Drupal\search_api\Display\DisplayInterface', 'Drupal\search_api\Annotation\SearchApiDisplay');
+    $this->setCacheBackend($cache_backend, 'search_api_displays');
+  }
+
+  /**
+   * Returns all known displays.
+   *
+   * @return \Drupal\search_api\Display\DisplayInterface[]
+   *   An array of display plugins, keyed by type identifier.
+   */
+  public function getInstances() {
+    if ($this->displays === NULL) {
+      $this->displays = array();
+
+      foreach ($this->getDefinitions() as $name => $display_definition) {
+        if (class_exists($display_definition['class']) && empty($this->displays[$name])) {
+          $display = $this->createInstance($name);
+          $this->displays[$name] = $display;
+        }
+      }
+    }
+
+    return $this->displays;
+  }
+
+}
diff --git a/src/Plugin/search_api/display/ViewsPageDisplay.php b/src/Plugin/search_api/display/ViewsPageDisplay.php
new file mode 100644
index 0000000..44ec510
--- /dev/null
+++ b/src/Plugin/search_api/display/ViewsPageDisplay.php
@@ -0,0 +1,15 @@
+<?php
+
+namespace Drupal\search_api\Plugin\search_api\display;
+
+use Drupal\search_api\Display\DisplayPluginBase;
+
+/**
+ * Represents a views page display.
+ *
+ * @SearchApiDisplay(
+ *   id = "views_page",
+ *   deriver = "Drupal\search_api\Plugin\search_api\display\ViewsPageDisplayDeriver"
+ * )
+ */
+class ViewsPageDisplay extends DisplayPluginBase {}
diff --git a/src/Plugin/search_api/display/ViewsPageDisplayDeriver.php b/src/Plugin/search_api/display/ViewsPageDisplayDeriver.php
new file mode 100644
index 0000000..7564c76
--- /dev/null
+++ b/src/Plugin/search_api/display/ViewsPageDisplayDeriver.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\search_api\Plugin\search_api\display;
+
+use Drupal\Component\Plugin\Exception\PluginNotFoundException;
+use Drupal\Component\Plugin\PluginBase;
+use Drupal\search_api\Display\DisplayDeriverBase;
+use Drupal\search_api\Plugin\views\query\SearchApiQuery;
+
+/**
+ * Derives a display plugin definition for every Search API views page.
+ *
+ * @see \Drupal\search_api\Plugin\search_api\display\ViewsPageDisplay
+ */
+class ViewsPageDisplayDeriver extends DisplayDeriverBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDerivativeDefinitions($base_plugin_definition) {
+    $base_plugin_id = $base_plugin_definition['id'];
+
+    try {
+      /** @var \Drupal\Core\Entity\EntityStorageInterface $views_storage */
+      $views_storage = $this->entityTypeManager->getStorage('view');
+      $all_views = $views_storage->loadMultiple();
+    }
+    catch (PluginNotFoundException $e) {
+      return array();
+    }
+
+    if (!isset($this->derivatives[$base_plugin_id])) {
+      $plugin_derivatives = array();
+
+      /** @var \Drupal\views\Entity\View $view */
+      foreach ($all_views as $view) {
+        $index = SearchApiQuery::getIndexFromTable($view->get('base_table'));
+        if ($index) {
+          $displays = $view->get('display');
+          foreach ($displays as $name => $display_info) {
+            if ($display_info['display_plugin'] == "page") {
+              $machine_name = $base = $view->id() . '__' . $name;
+              // Make sure the machine name is unique. (Will almost always be
+              // the case, unless a view or page ID contains two consecutive
+              // underscores.)
+              $i = 0;
+              while (isset($plugin_derivatives[$machine_name])) {
+                $machine_name = $base . '_' . ++$i;
+              }
+
+              $label_arguments = array(
+                '%view_name' => $view->label(),
+                '%display_title' => $display_info['display_title']
+              );
+              $label = $this->t('View %view_name, display %display_title', $label_arguments);
+
+              $executable = $view->getExecutable();
+              $executable->setDisplay($name);
+              $display = $executable->getDisplay();
+              $plugin_derivatives[$machine_name] = array(
+                'id' => $base_plugin_id . PluginBase::DERIVATIVE_SEPARATOR . $machine_name,
+                'label' => $label,
+                'description' => $view->get('description') ? $this->t('%view_description - Represents the page display %display_title of view %view_name.', array('%view_name' => $view->label(), '%view_description' => $view->get('description'), '%display_title' => $display_info['display_title'])) : $this->t('Represents the page display %display_title of view %view_name.', array('%view_name' => $view->label(), '%display_title' => $display_info['display_title'])),
+                'view_id' => $view->id(),
+                'view_display' => $name,
+                'path' => $display->getPath(),
+                'index' => $index->id(),
+              ) + $base_plugin_definition;
+
+              $arguments = array(
+                '%view' => $view->label(),
+                '%display' => $display_info['display_title'],
+              );
+              $sources[] = $this->t('View name: %view. Display: %display', $arguments);
+            }
+          }
+        }
+      }
+      uasort($plugin_derivatives, array($this, 'compareDerivatives'));
+
+      $this->derivatives[$base_plugin_id] = $plugin_derivatives;
+    }
+    return $this->derivatives[$base_plugin_id];
+  }
+
+}
diff --git a/src/Plugin/views/query/SearchApiQuery.php b/src/Plugin/views/query/SearchApiQuery.php
index 805d345..81420b4 100644
--- a/src/Plugin/views/query/SearchApiQuery.php
+++ b/src/Plugin/views/query/SearchApiQuery.php
@@ -199,6 +199,15 @@ public function init(ViewExecutable $view, DisplayPluginBase $display, array &$o
       $this->query->addTag('views_' . $view->id());
       $this->query->setOption('search_api_view', $view);
 
+      // We only provide a display plugin for Views page displays.
+      // @todo figure out how to allow new displays for other views display
+      //   types to be added. Do we need a hook for this?
+      if ($display->getPluginId() == 'page') {
+        // Load the Search API display and attach it to the query.
+        $display_plugin_manager = \Drupal::service('plugin.manager.search_api.display');
+        $search_api_display = $display_plugin_manager->createInstance('views_page:' . $view->id() . '__' . $view->current_display);
+        $this->query->setOption('search_api_display', $search_api_display);
+      }
     }
     catch (\Exception $e) {
       $this->abort($e->getMessage());
diff --git a/src/Tests/ViewsTest.php b/src/Tests/ViewsTest.php
index 8002dc3..2afb29a 100644
--- a/src/Tests/ViewsTest.php
+++ b/src/Tests/ViewsTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\search_api\Tests;
 
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Url;
 use Drupal\search_api\Entity\Index;
 use Drupal\search_api\Utility;
 
@@ -169,6 +170,14 @@ public function testView() {
       'keywords_op' => '>=',
     );
     $this->checkResults($query, array(1, 5), 'Search with arguments and filters', 'entity:entity_test/all/orange');
+
+    // Make sure there was a display plugin created for this view.
+    $displays = \Drupal::getContainer()->get('plugin.manager.search_api.display')->getInstances();
+    $display_id = 'views_page:search_api_test_view__page_1';
+    $this->assertEqual(array($display_id), array_keys($displays), 'A display plugin was created for the test view.');
+    $view_url = Url::fromUserInput('/search-api-test')->toString();
+    $this->assertEqual($view_url, $displays[$display_id]->getPath()->toString(), 'Display returns the correct path.');
+    $this->assertEqual('database_search_index', $displays[$display_id]->getIndex()->id(), 'Display returns the correct search index.');
   }
 
   /**
