diff --git a/homeassistant/components/group.py b/homeassistant/components/group.py
index c4cd177925ddccf2c419b0fb285cf1d637197510..41901d87e862f44af976574a1ac9cecc7d0be10e 100644
--- a/homeassistant/components/group.py
+++ b/homeassistant/components/group.py
@@ -46,12 +46,12 @@ def _conf_preprocess(value):
 
 
 CONFIG_SCHEMA = vol.Schema({
-    DOMAIN: {cv.match_all: vol.Schema(vol.All(_conf_preprocess, {
+    DOMAIN: cv.ordered_dict(vol.All(_conf_preprocess, {
         vol.Optional(CONF_ENTITIES): vol.Any(cv.entity_ids, None),
         CONF_VIEW: cv.boolean,
         CONF_NAME: cv.string,
         CONF_ICON: cv.icon,
-    }))}
+    }, cv.match_all))
 }, extra=vol.ALLOW_EXTRA)
 
 # List of ON/OFF state tuples for groupable states
diff --git a/homeassistant/helpers/config_validation.py b/homeassistant/helpers/config_validation.py
index 1be157c789de7d95a637d56c713b8df42de4a598..009736024a1ef6f5a24d46c31d98f38b03adce37 100644
--- a/homeassistant/helpers/config_validation.py
+++ b/homeassistant/helpers/config_validation.py
@@ -1,4 +1,5 @@
 """Helpers for config validation using voluptuous."""
+from collections import OrderedDict
 from datetime import timedelta
 import os
 from urllib.parse import urlparse
@@ -290,6 +291,27 @@ def url(value: Any) -> str:
     raise vol.Invalid('invalid url')
 
 
+def ordered_dict(value_validator, key_validator=match_all):
+    """Validate an ordered dict validator that maintains ordering.
+
+    value_validator will be applied to each value of the dictionary.
+    key_validator (optional) will be applied to each key of the dictionary.
+    """
+    item_validator = vol.Schema({key_validator: value_validator})
+
+    def validator(value):
+        """Validate ordered dict."""
+        config = OrderedDict()
+
+        for key, val in value.items():
+            v_res = item_validator({key: val})
+            config.update(v_res)
+
+        return config
+
+    return validator
+
+
 # Validator helpers
 
 def key_dependency(key, dependency):
diff --git a/tests/components/test_group.py b/tests/components/test_group.py
index e82190a3f2950c54d179dea342e2a4ed24d67c5c..6c601a411fb26b2bd847efaa8d9796a04e16b9a1 100644
--- a/tests/components/test_group.py
+++ b/tests/components/test_group.py
@@ -1,5 +1,6 @@
 """The tests for the Group components."""
 # pylint: disable=protected-access,too-many-public-methods
+from collections import OrderedDict
 import unittest
 from unittest.mock import patch
 
@@ -220,16 +221,16 @@ class TestComponentsGroup(unittest.TestCase):
         test_group = group.Group(
             self.hass, 'init_group', ['light.Bowl', 'light.Ceiling'], False)
 
-        _setup_component(self.hass, 'group', {'group': {
-                    'second_group': {
+        group_conf = OrderedDict()
+        group_conf['second_group'] = {
                         'entities': 'light.Bowl, ' + test_group.entity_id,
                         'icon': 'mdi:work',
                         'view': True,
-                    },
-                    'test_group': 'hello.world,sensor.happy',
-                    'empty_group': {'name': 'Empty Group', 'entities': None},
-                }
-            })
+                    }
+        group_conf['test_group'] = 'hello.world,sensor.happy'
+        group_conf['empty_group'] = {'name': 'Empty Group', 'entities': None}
+
+        _setup_component(self.hass, 'group', {'group': group_conf})
 
         group_state = self.hass.states.get(
             group.ENTITY_ID_FORMAT.format('second_group'))
@@ -241,6 +242,7 @@ class TestComponentsGroup(unittest.TestCase):
                          group_state.attributes.get(ATTR_ICON))
         self.assertTrue(group_state.attributes.get(group.ATTR_VIEW))
         self.assertTrue(group_state.attributes.get(ATTR_HIDDEN))
+        self.assertEqual(1, group_state.attributes.get(group.ATTR_ORDER))
 
         group_state = self.hass.states.get(
             group.ENTITY_ID_FORMAT.format('test_group'))
@@ -251,6 +253,7 @@ class TestComponentsGroup(unittest.TestCase):
         self.assertIsNone(group_state.attributes.get(ATTR_ICON))
         self.assertIsNone(group_state.attributes.get(group.ATTR_VIEW))
         self.assertIsNone(group_state.attributes.get(ATTR_HIDDEN))
+        self.assertEqual(2, group_state.attributes.get(group.ATTR_ORDER))
 
     def test_groups_get_unique_names(self):
         """Two groups with same name should both have a unique entity id."""
diff --git a/tests/helpers/test_config_validation.py b/tests/helpers/test_config_validation.py
index d9da2c51da79e39e221628888fb0a0a4c7305747..60b14757378e5a84e106f19a53ca02ab1d57d6fc 100644
--- a/tests/helpers/test_config_validation.py
+++ b/tests/helpers/test_config_validation.py
@@ -1,3 +1,5 @@
+"""Test config validators."""
+from collections import OrderedDict
 from datetime import timedelta
 import os
 import tempfile
@@ -367,3 +369,51 @@ def test_has_at_least_one_key():
 
     for value in ({'beer': None}, {'soda': None}):
         schema(value)
+
+
+def test_ordered_dict_order():
+    """Test ordered_dict validator."""
+    schema = vol.Schema(cv.ordered_dict(int, cv.string))
+
+    val = OrderedDict()
+    val['first'] = 1
+    val['second'] = 2
+
+    validated = schema(val)
+
+    assert isinstance(validated, OrderedDict)
+    assert ['first', 'second'] == list(validated.keys())
+
+
+def test_ordered_dict_key_validator():
+    """Test ordered_dict key validator."""
+    schema = vol.Schema(cv.ordered_dict(cv.match_all, cv.string))
+
+    with pytest.raises(vol.Invalid):
+        schema({None: 1})
+
+    schema({'hello': 'world'})
+
+    schema = vol.Schema(cv.ordered_dict(cv.match_all, int))
+
+    with pytest.raises(vol.Invalid):
+        schema({'hello': 1})
+
+    schema({1: 'works'})
+
+
+def test_ordered_dict_value_validator():
+    """Test ordered_dict validator."""
+    schema = vol.Schema(cv.ordered_dict(cv.string))
+
+    with pytest.raises(vol.Invalid):
+        schema({'hello': None})
+
+    schema({'hello': 'world'})
+
+    schema = vol.Schema(cv.ordered_dict(int))
+
+    with pytest.raises(vol.Invalid):
+        schema({'hello': 'world'})
+
+    schema({'hello': 5})