diff --git a/core/modules/views/config/schema/views.data_types.schema.yml b/core/modules/views/config/schema/views.data_types.schema.yml
index 3e1c25b..eb352c4 100644
--- a/core/modules/views/config/schema/views.data_types.schema.yml
+++ b/core/modules/views/config/schema/views.data_types.schema.yml
@@ -797,8 +797,11 @@ views_filter:
             - type: integer
               label: 'Default'
         group_items:
-          type: views.filter.group_items.[plugin_id]
+          type: sequence
           label: 'Group items'
+          sequence:
+            - type: views.filter.group_item.[%parent.%parent.%parent.plugin_id]
+              label: 'Group item'
     plugin_id:
       type: string
       label: 'Plugin ID'
@@ -806,21 +809,19 @@ views_filter:
       type: string
       label: 'Provider'
 
-views_filter_group_items:
-  type: sequence
-  sequence:
-    - type: mapping
-      label: 'Group item'
-      mapping:
-        title:
-          type: label
-          label: 'Label'
-        operator:
-          type: string
-          label: 'Operator'
-        value:
-          type: label
-          label: 'Value'
+views_filter_group_item:
+  type: mapping
+  label: 'Group item'
+  mapping:
+    title:
+      type: label
+      label: 'Label'
+    operator:
+      type: string
+      label: 'Operator'
+    value:
+      type: label
+      label: 'Value'
 
 views_relationship:
   type: mapping
diff --git a/core/modules/views/config/schema/views.filter.schema.yml b/core/modules/views/config/schema/views.filter.schema.yml
index 537ba81..964c46c 100644
--- a/core/modules/views/config/schema/views.filter.schema.yml
+++ b/core/modules/views/config/schema/views.filter.schema.yml
@@ -31,12 +31,16 @@ views.filter.combine:
         - type: string
           label: 'Field'
 
-views.filter.date:
-  type: views.filter.numeric
+views.filter_value.date:
+  type: views.filter_value.numeric
   label: 'Date'
+  mapping:
+    type:
+      type: string
+      label: 'Type'
 
-views.filter.groupby_numeric:
-  type: views.filter.numeric
+views.filter_value.groupby_numeric:
+  type: views.filter_value.numeric
   label: 'Group by numeric'
 
 views.filter.in_operator:
@@ -75,29 +79,22 @@ views.filter.string:
       type: string
       label: 'Value'
 
-views.filter.numeric:
-  type: views_filter
+views.filter_value.numeric:
+  type: mapping
   label: 'Numeric'
   mapping:
+    min:
+      type: string
+      label: 'Min'
+    max:
+      type: string
+      label: 'And max'
     value:
-      type: mapping
-      label: 'Operator'
-      mapping:
-        min:
-          type: string
-          label: 'Min'
-        max:
-          type: string
-          label: 'And max'
-        value:
-          type: string
-          label: 'Value'
-        type:
-          type: string
-          label: 'Value type'
+      type: string
+      label: 'Value'
 
-views.filter.equality:
-  type: views.filter.numeric
+views.filter_value.equality:
+  type: views.filter_value.numeric
   label: 'Equality'
 
 views.filter.many_to_one:
@@ -121,17 +118,23 @@ views.filter.standard:
   type: views_filter
   label: 'Standard'
 
-views.filter.group_items.*:
-  type: views_filter_group_items
+views.filter.group_item.*:
+  type: views_filter_group_item
   label: 'Default'
 
-views.filter.group_items.string:
-  type: views_filter_group_items
-  label: 'String group items'
+views.filter.group_item.numeric:
+  type: views_filter_group_item
+  label: 'Group items'
+  mapping:
+    value:
+      type: views.filter_value.numeric
 
-views.filter.group_items.boolean:
-  type: views_filter_group_items
+views.filter.group_item.date:
+  type: views_filter_group_item
   label: 'Group items'
+  mapping:
+    value:
+      type: views.filter_value.date
 
 # Schema for the views filter value.
 
diff --git a/core/modules/views/src/Plugin/views/filter/Date.php b/core/modules/views/src/Plugin/views/filter/Date.php
index 7e5417f..1944e1f 100644
--- a/core/modules/views/src/Plugin/views/filter/Date.php
+++ b/core/modules/views/src/Plugin/views/filter/Date.php
@@ -136,7 +136,12 @@ public function acceptExposedInput($input) {
     }
 
     // Store this because it will get overwritten.
-    $type = $this->value['type'];
+    if ($this->isAGroup()) {
+      $type = $this->group_info['type'];
+    }
+    else {
+      $type = $this->value['type'];
+    }
     $rc = parent::acceptExposedInput($input);
 
     // Don't filter if value(s) are empty.
diff --git a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
index 3366469..07dea00 100644
--- a/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -988,10 +988,12 @@ protected function buildExposedFiltersGroupForm(&$form, FormStateInterface $form
       foreach (Element::children($row['value']) as $children) {
         $has_state = FALSE;
         $states = array();
-        foreach ($row['value'][$children]['#states']['visible'] as $key => $state) {
-          if (isset($state[':input[name="options[operator]"]'])) {
-            $has_state = TRUE;
-            $states[$key] = $state[':input[name="options[operator]"]']['value'];
+        if (!empty($row['value'][$children]['#states']['visible'])) {
+          foreach ($row['value'][$children]['#states']['visible'] as $key => $state) {
+            if (isset($state[':input[name="options[operator]"]'])) {
+              $has_state = TRUE;
+              $states[$key] = $state[':input[name="options[operator]"]']['value'];
+            }
           }
         }
         if ($has_state) {
@@ -1003,10 +1005,10 @@ protected function buildExposedFiltersGroupForm(&$form, FormStateInterface $form
           }
 
           $row['value'][$children]['#title'] = '';
+        }
 
-          if (!empty($this->options['group_info']['group_items'][$item_id]['value'][$children])) {
-            $row['value'][$children]['#default_value'] = $this->options['group_info']['group_items'][$item_id]['value'][$children];
-          }
+        if (!empty($this->options['group_info']['group_items'][$item_id]['value'][$children])) {
+          $row['value'][$children]['#default_value'] = $this->options['group_info']['group_items'][$item_id]['value'][$children];
         }
         $without_children = FALSE;
       }
diff --git a/core/modules/views/src/Tests/Handler/FilterDateTest.php b/core/modules/views/src/Tests/Handler/FilterDateTest.php
index c538bc3..8dd88f9 100644
--- a/core/modules/views/src/Tests/Handler/FilterDateTest.php
+++ b/core/modules/views/src/Tests/Handler/FilterDateTest.php
@@ -51,6 +51,7 @@ protected function testDateFilter() {
     $this->_testOffset();
     $this->_testBetween();
     $this->_testUiValidation();
+    $this->_testFilterDateUI();
   }
 
   /**
@@ -158,4 +159,60 @@ protected function _testUiValidation() {
     $this->assertText(t('Invalid date format.'), 'Make sure that validation is runned and the invalidate date format is identified.');
   }
 
+  /**
+   * Test grouped date filter.
+   */
+  protected function _testFilterDateUI() {
+    $this->drupalLogin($this->drupalCreateUser(array('administer views')));
+    $this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
+    $this->drupalPostForm(NULL, array(), t('Expose filter'));
+    $this->drupalPostForm(NULL, array(), t('Grouped filters'));
+
+    $edit = array();
+    $edit['options[group_info][group_items][1][title]'] = 'simple-offset';
+    $edit['options[group_info][group_items][1][operator]'] = '>';
+    $edit['options[group_info][group_items][1][value][type]'] = 'offset';
+    $edit['options[group_info][group_items][1][value][value]'] = '+1 hour';
+    $edit['options[group_info][group_items][2][title]'] = 'between-offset';
+    $edit['options[group_info][group_items][2][operator]'] = 'between';
+    $edit['options[group_info][group_items][2][value][type]'] = 'offset';
+    $edit['options[group_info][group_items][2][value][min]'] = '+1 hour';
+    $edit['options[group_info][group_items][2][value][max]'] = '+2 days';
+    $edit['options[group_info][group_items][3][title]'] = 'between-date';
+    $edit['options[group_info][group_items][3][operator]'] = 'between';
+    $edit['options[group_info][group_items][3][value][min]'] = format_date(150000, 'custom', 'Y-m-d H:s');
+    $edit['options[group_info][group_items][3][value][max]'] = format_date(250000, 'custom', 'Y-m-d H:s');
+
+    $this->drupalPostForm(NULL, $edit, t('Apply'));
+
+    $this->drupalGet('admin/structure/views/nojs/handler/test_filter_date_between/default/filter/created');
+    foreach ($edit as $name => $value) {
+      $this->assertFieldByName($name, $value);
+      if (strpos($name, '[value][type]')) {
+        $radio = $this->cssSelect('input[name="' . $name . '"][checked="checked"][type="radio"]');
+        $this->assertEqual((string) $radio[0]['value'], $value);
+      }
+    }
+
+    // Test that the exposed filter works as expected.
+    $this->drupalGet('admin/structure/views/view/test_filter_date_between/edit');
+    $this->drupalPostForm(NULL, array(), t('Update preview'));
+    $results = $this->cssSelect('.view-content .field-content');
+    $this->assertEqual(count($results), 4);
+    $this->drupalPostForm(NULL, array('created' => '1'), t('Update preview'));
+    $results = $this->cssSelect('.view-content .field-content');
+    $this->assertEqual(count($results), 1);
+    $this->assertEqual((string) $results[0], $this->nodes[3]->id());
+    $this->drupalPostForm(NULL, array('created' => '2'), t('Update preview'));
+    $results = $this->cssSelect('.view-content .field-content');
+    $this->assertEqual(count($results), 1);
+    $this->assertEqual((string) $results[0], $this->nodes[3]->id());
+    $this->drupalPostForm(NULL, array('created' => '3'), t('Update preview'));
+    $results = $this->cssSelect('.view-content .field-content');
+    $this->assertEqual(count($results), 1);
+    $this->assertEqual((string) $results[0], $this->nodes[1]->id());
+
+    $this->drupalPostForm('admin/structure/views/view/test_filter_date_between', array(), t('Save'));
+  }
+
 }
