diff --git a/core/lib/Drupal/Core/Form/FormBuilder.php b/core/lib/Drupal/Core/Form/FormBuilder.php
index 0f31a1c..c679788 100644
--- a/core/lib/Drupal/Core/Form/FormBuilder.php
+++ b/core/lib/Drupal/Core/Form/FormBuilder.php
@@ -236,10 +236,13 @@ public function buildForm($form_id, FormStateInterface &$form_state) {
       //   not desired.
       // - temporary: Any assigned data is expected to survives within the same
       //   page request.
+      // - input: Any user submitted data is expected to survive within the same
+      //   page request.
       if ($check_cache) {
         $cache_form_state = $form_state->getCacheableArray();
         $cache_form_state['always_process'] = $form_state->getAlwaysProcess();
         $cache_form_state['temporary'] = $form_state->getTemporary();
+        $cache_form_state['input'] = $form_state->getUserInput();
         $form_state = $form_state_before_retrieval;
         $form_state->setFormState($cache_form_state);
       }
diff --git a/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php b/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php
index 292a2e3..9c5c8ea 100644
--- a/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php
+++ b/core/modules/views/src/Plugin/views/wizard/WizardPluginBase.php
@@ -323,7 +323,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         '#title' => $this->t('Feed row style'),
         '#type' => 'select',
         '#options' => $feed_row_options,
-        '#default_value' => key($feed_row_options),
         '#access' => (count($feed_row_options) > 1),
         '#states' => array(
           'visible' => array(
@@ -334,6 +333,9 @@ public function buildForm(array $form, FormStateInterface $form_state) {
         '#suffix' => '</div>',
       );
     }
+    // Dynamically determine the feed row style as it varies by base table.
+    $feed_style_form = &$form['displays']['page']['options']['feed_properties'];
+    $feed_style_form['row_plugin']['#default_value'] = static::getSelected($form_state, array('page', 'feed_properties', 'row_plugin'), key($feed_row_options), $feed_style_form['row_plugin']);
 
     // Only offer the block settings if the module is enabled.
     if (\Drupal::moduleHandler()->moduleExists('block')) {
@@ -469,7 +471,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    *
    * @param \Drupal\Core\Form\FormStateInterface $form_state
    *   The current state of the form.
-   * @param $parents
+   * @param array $parents
    *   An array of parent keys that point to the part of the submitted form
    *   values that are expected to contain the element's value (in the case where
    *   this form element was actually submitted). In a simple case (assuming
@@ -480,16 +482,16 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    * @param $default_value
    *   The default value to return if the #select element does not currently have
    *   a proper value set based on the submitted input.
-   * @param $element
+   * @param array $element
    *   An array representing the current version of the #select element within
    *   the form.
    *
-   * @return
+   * @return string
    *   The current value of the #select element. A common use for this is to feed
    *   it back into $element['#default_value'] so that the form will be rendered
    *   with the correct value selected.
    */
-  public static function getSelected(FormStateInterface $form_state, $parents, $default_value, $element) {
+  public static function getSelected(FormStateInterface $form_state, array $parents, $default_value, array $element) {
     // For now, don't trust this to work on anything but a #select element.
     if (!isset($element['#type']) || $element['#type'] != 'select' || !isset($element['#options'])) {
       return $default_value;
@@ -517,8 +519,28 @@ public static function getSelected(FormStateInterface $form_state, $parents, $de
       // option A is no longer one of the choices. In that case, we don't want to
       // use the value that was submitted anymore but rather fall back to the
       // default value.
-      if ($key_exists && in_array($submitted, array_keys($element['#options']))) {
-        return $submitted;
+      if ($key_exists) {
+        $option_exists = in_array($submitted, array_keys($element['#options']));
+        // If this value is invalid or if the user-submitted value has changed,
+        // remove all other options in that set of values. Only manipulate the
+        // user input during the initial form build, not during any subsequent
+        // rebuild.
+        if ((!$option_exists || $submitted !== $default_value) && !$form_state->isRebuilding()) {
+          // If this is a not a top-level element, traverse up one level.
+          $original_parents = $parents;
+          if (count($parents) > 1) {
+            array_pop($parents);
+          }
+          NestedArray::unsetValue($user_input, $parents);
+          // Restore the submitted value to the input.
+          if ($option_exists) {
+            NestedArray::setValue($user_input, $original_parents, $submitted);
+          }
+        }
+
+        if ($option_exists) {
+          return $submitted;
+        }
       }
     }
 
diff --git a/core/modules/views/src/Tests/Wizard/TaggedWithTest.php b/core/modules/views/src/Tests/Wizard/TaggedWithTest.php
index caf95be..ce26716 100644
--- a/core/modules/views/src/Tests/Wizard/TaggedWithTest.php
+++ b/core/modules/views/src/Tests/Wizard/TaggedWithTest.php
@@ -196,11 +196,11 @@ function testTaggedWithByNodeType() {
     $this->drupalPostForm('admin/structure/views/add', $view, t('Update "of type" choice'));
     $this->assertFieldByXpath($tags_xpath);
     $view['show[type]'] = $this->nodeTypeWithoutTags->id();
-    $this->drupalPostForm(NULL, $view, t('Update "of type" choice'));
+    $this->drupalPostForm(NULL, $view, t('Update "of type" choice (2)'));
     $this->assertNoFieldByXpath($tags_xpath);
 
     // If we add an instance of the tagging field to the second node type, the
-    // "tagged with" form element should not appear for it too.
+    // "tagged with" form element should now appear for it too.
     entity_create('field_config', array(
       'field_name' => $this->tagFieldName,
       'entity_type' => 'node',
@@ -225,7 +225,7 @@ function testTaggedWithByNodeType() {
     $this->drupalPostForm('admin/structure/views/add', $view, t('Update "of type" choice'));
     $this->assertFieldByXpath($tags_xpath);
     $view['show[type]'] = $this->nodeTypeWithoutTags->id();
-    $this->drupalPostForm(NULL, $view, t('Update "of type" choice'));
+    $this->drupalPostForm(NULL, $view, t('Update "of type" choice (2)'));
     $this->assertFieldByXpath($tags_xpath);
   }
 
diff --git a/core/modules/views/tests/src/Unit/WizardPluginBaseTest.php b/core/modules/views/tests/src/Unit/WizardPluginBaseTest.php
new file mode 100644
index 0000000..ed30219
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/WizardPluginBaseTest.php
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\views\Unit\WizardPluginBaseTest.
+ */
+
+namespace Drupal\Tests\views\Unit;
+
+use Drupal\Core\Form\FormState;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\wizard\WizardPluginBase;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\wizard\WizardPluginBase
+ *
+ * @group views
+ */
+class WizardPluginBaseTest extends UnitTestCase {
+
+  /**
+   * @covers ::getSelected
+   *
+   * @dataProvider providerTestGetSelected
+   */
+  public function testGetSelected($expected, $element = [], $parents = [], $user_input = [], $expected_user_input = []) {
+    $form_state = new FormState();
+    $form_state->setUserInput($user_input);
+
+    $actual = WizardPluginBase::getSelected($form_state, $parents, 'the_default_value', $element);
+    $this->assertSame($expected, $actual);
+    $this->assertSame($expected_user_input, $form_state->getUserInput());
+  }
+
+  /**
+   * Provides test data for testGetSelected().
+   */
+  public function providerTestGetSelected() {
+    $data = [];
+    // A form element with an invalid #type.
+    $data[] = [
+      'the_default_value',
+      [
+        '#type' => 'checkbox',
+      ],
+    ];
+    // A form element with no #options.
+    $data[] = [
+      'the_default_value',
+      [
+        '#type' => 'select',
+      ],
+    ];
+    // A valid form element with no user input.
+    $data[] = [
+      'the_default_value',
+      [
+        '#type' => 'select',
+        '#options' => [
+          'option1' => 'Option 1',
+        ],
+      ],
+    ];
+    // A valid form element with user input that doesn't correspond to it.
+    $data[] = [
+      'the_default_value',
+      [
+        '#type' => 'select',
+        '#options' => [
+          'option1' => 'Option 1',
+        ],
+      ],
+      ['foo', 'bar'],
+      ['foo' => ['foo' => 'value1']],
+      ['foo' => ['foo' => 'value1']],
+    ];
+    // A valid form element that is at the top-level of the form.
+    $data[] = [
+      'the_default_value',
+      [
+        '#type' => 'select',
+        '#options' => [
+          'option1' => 'Option 1',
+        ],
+      ],
+      ['foo'],
+      ['foo' => ['bar' => 'value1']],
+    ];
+    // A valid form element that has multiple invalid values with the same
+    // parent.
+    $data[] = [
+      'the_default_value',
+      [
+        '#type' => 'select',
+        '#options' => [
+          'option1' => 'Option 1',
+        ],
+      ],
+      ['foo', 'bar'],
+      ['foo' => ['bar' => 'value1', 'baz' => 'value2']],
+    ];
+    // A valid form element with a valid dynamic value that matches the default
+    // value.
+    $data[] = [
+      'the_default_value',
+      [
+        '#type' => 'select',
+        '#options' => [
+          'the_default_value' => 'Option 1',
+        ],
+      ],
+      ['foo', 'bar'],
+      ['foo' => ['bar' => 'the_default_value']],
+      ['foo' => ['bar' => 'the_default_value']],
+    ];
+    // A valid form element with a valid dynamic value that does not match the
+    // default value.
+    $data[] = [
+      'option1',
+      [
+        '#type' => 'select',
+        '#options' => [
+          'option1' => 'Option 1',
+        ],
+      ],
+      ['foo', 'bar'],
+      ['foo' => ['bar' => 'option1']],
+      ['foo' => ['bar' => 'option1']],
+    ];
+    return $data;
+  }
+
+}
diff --git a/core/modules/views_ui/admin.inc b/core/modules/views_ui/admin.inc
index 80ade9b..c6ab2b2 100644
--- a/core/modules/views_ui/admin.inc
+++ b/core/modules/views_ui/admin.inc
@@ -52,10 +52,6 @@ function views_ui_add_ajax_trigger(&$wrapping_element, $trigger_key, $refresh_pa
   $triggering_element = &$wrapping_element[$trigger_key];
   $triggering_element['#ajax']['callback'] = 'views_ui_ajax_update_form';
 
-  // Specify the #ajax URL in order to retain form caching.
-  // @todo Remove this in https://www.drupal.org/node/2500523.
-  $triggering_element['#ajax']['url'] = Url::fromRoute('system.ajax');
-
   // We do not use \Drupal\Component\Utility\Html::getUniqueId() to get an ID
   // for the AJAX wrapper, because it remembers IDs across AJAX requests (and
   // won't reuse them), but in our case we need to use the same ID from request
