diff --git a/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php b/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
index a92c58315f1099bcb85d9c2287d3c9e847850d47..9ac576e433e20cf8c0c1d75b34e6fedc76c389d2 100644
--- a/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
+++ b/lib/Drupal/views/Plugin/views/display/DisplayPluginBase.php
@@ -38,6 +38,13 @@ abstract class DisplayPluginBase extends PluginBase {
 
   var $handlers = array();
 
+  /**
+   * An array of instantiated plugins used in this display.
+   *
+   * @var array
+   */
+  protected $plugins = array();
+
   /**
    * Stores all available display extenders.
    */
@@ -722,11 +729,7 @@ public function getOption($option) {
    * @return bool
    */
   public function usesFields() {
-    $style = $this->getOption('style');
-    $plugin = $this->getPlugin('style', $style['type']);
-    if ($plugin) {
-      return $plugin->usesFields();
-    }
+    return $this->getPlugin('style')->usesFields();
   }
 
   /**
@@ -734,54 +737,35 @@ public function usesFields() {
    *
    * @param string $type
    *   The type of the plugin.
-   * @param string $name
-   *   The name of the plugin defined in hook_views_plugins.
    *
-   * @return views_plugin|FALSE
-   */
-  public function getPlugin($type = 'style', $name = NULL) {
-    static $cache = array();
-    if (!isset($cache[$type][$name])) {
-      switch ($type) {
-        case 'query':
-          $views_data = views_fetch_data($this->view->storage->base_table);
-          $name = !empty($views_data['table']['base']['query class']) ? $views_data['table']['base']['query class'] : 'views_query';
-        default:
-          $option_name = $type;
-          $options = $this->getOption($type);
-          if (!$name) {
-            $name = $options['type'];
-          }
+   * @return Drupal\views\Plugin\views\PluginBase
+   */
+  public function getPlugin($type) {
+    // Look up the name to attempt to load it from the static cache.
+    $options = $this->getOption($type);
+    $name = $options['type'];
 
-          $options = $options['options'];
+    if (!isset($this->plugins[$type][$name])) {
+      $views_data = views_fetch_data($this->view->storage->base_table);
+      if ($type == 'query') {
+        $name = !empty($views_data['table']['base']['query class']) ? $views_data['table']['base']['query class'] : 'views_query';
       }
 
-      if ($type != 'query') {
-        $plugin = views_get_plugin($type, $name);
-      }
-      else {
-        $plugin = views_get_plugin('query', $name);
-      }
+      $plugin = drupal_container()->get("plugin.manager.views.$type")->createInstance($name);
 
-      if (!$plugin) {
-        return;
-      }
       if ($type != 'query') {
-        $plugin->init($this->view, $this, $options);
+        $plugin->init($this->view, $this, $options['options']);
       }
       else {
-        $display_id = $this->isDefaulted($option_name) ? $this->display['id'] : 'default';
-
         if (!isset($this->base_field)) {
-          $views_data = views_fetch_data($this->view->storage->base_table);
           $this->view->storage->base_field = !empty($views_data['table']['base']['field']) ? $views_data['table']['base']['field'] : '';
         }
-        $plugin->init($this->view->storage->base_table, $this->view->storage->base_field, $options);
+        $plugin->init($this->view->storage->base_table, $this->view->storage->base_field, $options['options']);
       }
-      $cache[$type][$name] = $plugin;
+      $this->plugins[$type][$name] = $plugin;
     }
 
-    return $cache[$type][$name];
+    return $this->plugins[$type][$name];
   }
 
   /**
@@ -1056,12 +1040,9 @@ public function optionsSummary(&$categories, &$options) {
       'desc' => t('Change the title that this display will use.'),
     );
 
-    $style_options = $this->getOption('style');
-    $name = $style_options['type'];
-    $style_plugin = views_get_plugin_definition('style', $name);
     $style_plugin_instance = $this->getPlugin('style');
-    $style_summary = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->summaryTitle();
-    $style_title = empty($style_plugin['title']) ? t('Missing style plugin') : $style_plugin_instance->pluginTitle();
+    $style_summary = empty($style_plugin_instance->definition['title']) ? t('Missing style plugin') : $style_plugin_instance->summaryTitle();
+    $style_title = empty($style_plugin_instance->definition['title']) ? t('Missing style plugin') : $style_plugin_instance->pluginTitle();
 
     $style = '';
 
@@ -1079,12 +1060,9 @@ public function optionsSummary(&$categories, &$options) {
     }
 
     if ($style_plugin_instance->usesRowPlugin()) {
-      $row_options = $this->getOption('row');
-      $name = $row_options['type'];
-      $row_plugin = views_get_plugin_definition('row', $name);
-      $row_plugin_instance = $this->getPlugin('row', $name);
-      $row_summary = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->summaryTitle();
-      $row_title = empty($row_plugin['title']) ? t('Missing style plugin') : $row_plugin_instance->pluginTitle();
+      $row_plugin_instance = $this->getPlugin('row');
+      $row_summary = empty($row_plugin_instance->definition['title']) ? t('Missing style plugin') : $row_plugin_instance->summaryTitle();
+      $row_title = empty($row_plugin_instance->definition['title']) ? t('Missing style plugin') : $row_plugin_instance->pluginTitle();
 
       $options['row'] = array(
         'category' => 'format',
@@ -1570,15 +1548,14 @@ public function buildOptionsForm(&$form, &$form_state) {
         break;
       case 'style':
         $form['#title'] .= t('How should this view be styled');
-        $style = $this->getOption('style');
-        $form['style_plugin'] =  array(
+        $style_plugin = $this->getPlugin('style');
+        $form['style'] =  array(
           '#type' => 'radios',
           '#options' => views_fetch_plugin_names('style', $this->getStyleType(), array($this->view->storage->base_table)),
-          '#default_value' => $style['type'],
+          '#default_value' => $style_plugin->definition['id'],
           '#description' => t('If the style you choose has settings, be sure to click the settings button that will appear next to it in the View summary.'),
         );
 
-        $style_plugin = $this->getPlugin('style', $style['type']);
         if ($style_plugin->usesOptions()) {
           $form['markup'] = array(
             '#prefix' => '<div class="form-item description">',
@@ -1613,14 +1590,13 @@ public function buildOptionsForm(&$form, &$form_state) {
         break;
       case 'row':
         $form['#title'] .= t('How should each row in this view be styled');
-        $row = $this->getOption('row');
-        $form['row_plugin'] =  array(
+        $row_plugin_instance = $this->getPlugin('row');
+        $form['row'] =  array(
           '#type' => 'radios',
           '#options' => views_fetch_plugin_names('row', $this->getStyleType(), array($this->view->storage->base_table)),
-          '#default_value' => $row['type'],
+          '#default_value' => $row_plugin_instance->definition['id'],
         );
 
-        $row_plugin_instance = $this->getPlugin('row', $row['type']);
         if ($row_plugin_instance->usesOptions()) {
           $form['markup'] = array(
             '#prefix' => '<div class="form-item description">',
@@ -1770,8 +1746,7 @@ public function buildOptionsForm(&$form, &$form_state) {
           }
         }
 
-        $name = $this->getOption('style_plugin');
-        $plugin = $this->getPlugin('style', $name);
+        $plugin = $this->getPlugin('style');
         if ($plugin) {
           $funcs[] = $this->optionLink(t('Style output'), 'analyze-theme-style') . ': ' . $this->formatThemes($plugin->themeFunctions(), $plugin->additionalThemeFunctions());
           $themes = $plugin->additionalThemeFunctions();
@@ -1782,8 +1757,7 @@ public function buildOptionsForm(&$form, &$form_state) {
           }
 
           if ($plugin->usesRowPlugin()) {
-            $name = $this->getOption('row_plugin');
-            $row_plugin = $this->getPlugin('row', $name);
+            $row_plugin = $this->getPlugin('row');
             if ($row_plugin) {
               $funcs[] = $this->optionLink(t('Row style output'), 'analyze-theme-row') . ': ' . $this->formatThemes($row_plugin->themeFunctions());
               $themes = $row_plugin->additionalThemeFunctions();
@@ -1885,8 +1859,7 @@ public function buildOptionsForm(&$form, &$form_state) {
         $form['#title'] .= t('Theming information (style)');
         $output = '<p>' . t('Back to !info.', array('!info' => $this->optionLink(t('theming information'), 'analyze-theme'))) . '</p>';
 
-        $name = $this->getOption('style_plugin');
-        $plugin = $this->getPlugin('style', $name);
+        $plugin = $this->getPlugin('style');
 
         if (empty($plugin->definition['theme'])) {
           $output .= t('This display has no style theming information');
@@ -1913,8 +1886,7 @@ public function buildOptionsForm(&$form, &$form_state) {
         $form['#title'] .= t('Theming information (row style)');
         $output = '<p>' . t('Back to !info.', array('!info' => $this->optionLink(t('theming information'), 'analyze-theme'))) . '</p>';
 
-        $name = $this->getOption('row_plugin');
-        $plugin = $this->getPlugin('row', $name);
+        $plugin = $this->getPlugin('row');
 
         if (empty($plugin->definition['theme'])) {
           $output .= t('This display has no row style theming information');
@@ -2248,10 +2220,10 @@ public function submitOptionsForm(&$form, &$form_state) {
         // This if prevents resetting options to default if they don't change
         // the plugin.
         $row = $this->getOption('row');
-        if ($row['type'] != $form_state['values'][$section]['type']) {
-          $plugin = views_get_plugin('row', $form_state['values'][$section]['type']);
+        if ($row['type'] != $form_state['values'][$section]) {
+          $plugin = views_get_plugin('row', $form_state['values'][$section]);
           if ($plugin) {
-            $row = array('type' => $form_state['values'][$section]['type']);
+            $row = array('type' => $form_state['values'][$section]);
             $this->setOption($section, $row);
 
             // send ajax form to options page if we use it.
@@ -2265,10 +2237,10 @@ public function submitOptionsForm(&$form, &$form_state) {
         // This if prevents resetting options to default if they don't change
         // the plugin.
         $style = $this->getOption('style');
-        if ($style['type'] != $form_state['values'][$section]['type']) {
-          $plugin = views_get_plugin('style', $form_state['values'][$section]['type']);
+        if ($style['type'] != $form_state['values'][$section]) {
+          $plugin = views_get_plugin('style', $form_state['values'][$section]);
           if ($plugin) {
-            $row = array('type' => $form_state['values'][$section]['type']);
+            $row = array('type' => $form_state['values'][$section]);
             $this->setOption($section, $row);
             // send ajax form to options page if we use it.
             if ($plugin->usesOptions()) {
@@ -2596,8 +2568,7 @@ public function validate() {
     }
 
     // Validate style plugin
-    $name = $this->getOption('style_plugin');
-    $style = $this->getPlugin('style', $name);
+    $style = $this->getPlugin('style');
     if (empty($style)) {
       $errors[] = t('Display "@display" has an invalid style plugin.', array('@display' => $this->display['display_title']));
     }
diff --git a/lib/Drupal/views/Plugin/views/display/Feed.php b/lib/Drupal/views/Plugin/views/display/Feed.php
index 9a4165aaf889648a3fac0d6f11bfaf443bf92187..1af8deb154a6d5ac88b30f12d199cf5f3b57ee6d 100644
--- a/lib/Drupal/views/Plugin/views/display/Feed.php
+++ b/lib/Drupal/views/Plugin/views/display/Feed.php
@@ -240,8 +240,7 @@ public function attachTo($display_id) {
 
     // Defer to the feed style; it may put in meta information, and/or
     // attach a feed icon.
-    $name = $this->getOption('style_plugin');
-    $plugin = $this->getPlugin('style', $name);
+    $plugin = $this->getPlugin('style');
     if ($plugin) {
       $clone = $this->view->cloneView();
       $clone->setDisplay($this->display['id']);
diff --git a/lib/Drupal/views/Plugin/views/style/StylePluginBase.php b/lib/Drupal/views/Plugin/views/style/StylePluginBase.php
index 8f110673c92d037f4427c3065df5c2ef05a81039..65c83d84ff2787523446217aaa38fd04c7a2cf43 100644
--- a/lib/Drupal/views/Plugin/views/style/StylePluginBase.php
+++ b/lib/Drupal/views/Plugin/views/style/StylePluginBase.php
@@ -662,8 +662,7 @@ public function validate() {
     $errors = parent::validate();
 
     if ($this->usesRowPlugin()) {
-      $name = $this->displayHandler->getOption('row_plugin');
-      $plugin = $this->displayHandler->getPlugin('row', $name);
+      $plugin = $this->displayHandler->getPlugin('row');
       if (empty($plugin)) {
         $errors[] = t('Style @style requires a row style but the row plugin is invalid.', array('@style' => $this->definition['title']));
       }
diff --git a/lib/Drupal/views/Tests/UI/RowUITest.php b/lib/Drupal/views/Tests/UI/RowUITest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7d7b2457cc8f09877d1f5f17dd94a4c199e30834
--- /dev/null
+++ b/lib/Drupal/views/Tests/UI/RowUITest.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\views\Tests\UI\RowUITest.
+ */
+
+namespace Drupal\views\Tests\UI;
+
+/**
+ * Tests the UI of row plugins.
+ *
+ * @see Drupal\views_test_data\Plugin\views\row\RowTest.
+ */
+class RowUITest extends UITestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Row: UI',
+      'description' => 'Tests the UI of row plugins.',
+      'group' => 'Views UI',
+    );
+  }
+
+  /**
+   * Tests changing the row plugin and changing some options of a row.
+   */
+  public function testRowUI() {
+    $view = $this->getView();
+    $view_edit_url = "admin/structure/views/view/{$view->storage->name}/edit";
+
+    $row_plugin_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/row";
+    $row_options_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/row_options";
+
+    $this->drupalGet($row_plugin_url);
+    $this->assertFieldByName('row', 'fields', 'The default row plugin selected in the UI should be fields.');
+
+    $edit = array(
+      'row' => 'test_row'
+    );
+    $this->drupalPost(NULL, $edit, t('Apply'));
+    $this->assertFieldByName('row_options[test_option]', NULL, 'Make sure the custom settings form from the test plugin appears.');
+    $random_name = $this->randomName();
+    $edit = array(
+      'row_options[test_option]' => $random_name
+    );
+    $this->drupalPost(NULL, $edit, t('Apply'));
+    $this->drupalGet($row_options_url);
+    $this->assertFieldByName('row_options[test_option]', $random_name, 'Make sure the custom settings form field has the expected value stored.');
+
+    $this->drupalPost($view_edit_url, array(), t('Save'));
+    $this->assertLink(t('Test row plugin'), 0, 'Make sure the test row plugin is shown in the UI');
+
+    $view = views_get_view($view->storage->name);
+    $view->initDisplay();
+    $row = $view->display_handler->getOption('row');
+    $this->assertEqual($row['type'], 'test_row', 'Make sure that the test_row got saved as used row plugin.');
+    $this->assertEqual($row['options']['test_option'], $random_name, 'Make sure that the custom settings field got saved as expected.');
+  }
+
+}
diff --git a/lib/Drupal/views/Tests/UI/StyleUITest.php b/lib/Drupal/views/Tests/UI/StyleUITest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5255af9dc72f86b289bd8f19fbcaaa7916d13248
--- /dev/null
+++ b/lib/Drupal/views/Tests/UI/StyleUITest.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\views\Tests\UI\StyleUITest.
+ */
+
+namespace Drupal\views\Tests\UI;
+
+/**
+ * Tests the UI of style plugins.
+ *
+ * @see Drupal\views_test_data\Plugin\views\style\StyleTest.
+ */
+class StyleUITest extends UITestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Style: UI',
+      'description' => 'Tests the UI of style plugins.',
+      'group' => 'Views UI',
+    );
+  }
+
+  /**
+   * Tests changing the style plugin and changing some options of a style.
+   */
+  public function testStyleUI() {
+    $view = $this->getView();
+    $view_edit_url = "admin/structure/views/view/{$view->storage->name}/edit";
+
+    $style_plugin_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/style";
+    $style_options_url = "admin/structure/views/nojs/display/{$view->storage->name}/default/style_options";
+
+    $this->drupalGet($style_plugin_url);
+    $this->assertFieldByName('style', 'default', 'The default style plugin selected in the UI should be unformatted list.');
+
+    $edit = array(
+      'style' => 'test_style'
+    );
+    $this->drupalPost(NULL, $edit, t('Apply'));
+    $this->assertFieldByName('style_options[test_option]', NULL, 'Make sure the custom settings form from the test plugin appears.');
+    $random_name = $this->randomName();
+    $edit = array(
+      'style_options[test_option]' => $random_name
+    );
+    $this->drupalPost(NULL, $edit, t('Apply'));
+    $this->drupalGet($style_options_url);
+    $this->assertFieldByName('style_options[test_option]', $random_name, 'Make sure the custom settings form field has the expected value stored.');
+
+    $this->drupalPost($view_edit_url, array(), t('Save'));
+    $this->assertLink(t('Test style plugin'), 0, 'Make sure the test style plugin is shown in the UI');
+
+    $view = views_get_view($view->storage->name);
+    $view->initDisplay();
+    $style = $view->display_handler->getOption('style');
+    $this->assertEqual($style['type'], 'test_style', 'Make sure that the test_style got saved as used style plugin.');
+    $this->assertEqual($style['options']['test_option'], $random_name, 'Make sure that the custom settings field got saved as expected.');
+  }
+
+}
diff --git a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php
index 3176d6be84a88e0712f86afe143bb7bd31304f84..771ac8f32074fda587c82fb8ef82f7e632df372b 100644
--- a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php
+++ b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/row/RowTest.php
@@ -33,6 +33,29 @@ class RowTest extends RowPluginBase {
    */
   public $output;
 
+  /**
+   * Overrides Drupal\views\Plugin\views\row\RowPluginBase::defineOptions().
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+    $options['test_option'] = array('default' => '');
+
+    return $options;
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\row\RowPluginBase::buildOptionsForm().
+   */
+  public function buildOptionsForm(&$form, &$form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $form['test_option'] = array(
+      '#type' => 'textfield',
+      '#description' => t('This is a textfield for test_option.'),
+      '#default_value' => $this->options['test_option'],
+    );
+  }
+
   /**
    * Sets the output property.
    *
diff --git a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php
index 27b21933fae342cc543a445ca922b8c84563ca15..59dc396ad240da3e208d6cbe2014da88a494127b 100644
--- a/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php
+++ b/tests/views_test_data/lib/Drupal/views_test_data/Plugin/views/style/StyleTest.php
@@ -33,6 +33,29 @@ class StyleTest extends StylePluginBase {
    */
   public $output;
 
+  /**
+   * Overrides Drupal\views\Plugin\views\style\StylePluginBase::defineOptions().
+   */
+  protected function defineOptions() {
+    $options = parent::defineOptions();
+    $options['test_option'] = array('default' => '');
+
+    return $options;
+  }
+
+  /**
+   * Overrides Drupal\views\Plugin\views\style\StylePluginBase::buildOptionsForm().
+   */
+  public function buildOptionsForm(&$form, &$form_state) {
+    parent::buildOptionsForm($form, $form_state);
+
+    $form['test_option'] = array(
+      '#type' => 'textfield',
+      '#description' => t('This is a textfield for test_option.'),
+      '#default_value' => $this->options['test_option'],
+    );
+  }
+
   function usesRowPlugin() {
     return parent::usesRowPlugin();
   }
diff --git a/views_ui/lib/Drupal/views_ui/ViewUI.php b/views_ui/lib/Drupal/views_ui/ViewUI.php
index fcd5d2f1a46ae649e8e73799aa5a1913a127d9dd..6c92498833e109dff7eb06783380b19c66000da7 100644
--- a/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -917,8 +917,7 @@ public function getFormBucket($type, $display) {
         break;
       case 'field':
         // Fetch the style plugin info so we know whether to list fields or not.
-        $style = $this->displayHandlers[$display['id']]->getOption('style');
-        $style_plugin = $this->displayHandlers[$display['id']]->getPlugin('style', $style['type']);
+        $style_plugin = $this->displayHandlers[$display['id']]->getPlugin('style');
         $uses_fields = $style_plugin && $style_plugin->usesFields();
         if (!$uses_fields) {
           $build['fields'][] = array(