diff --git a/keystone/catalog/backends/kvs.py b/keystone/catalog/backends/kvs.py
deleted file mode 100644
index 644777ed2d..0000000000
--- a/keystone/catalog/backends/kvs.py
+++ /dev/null
@@ -1,371 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-
-from keystone import catalog
-from keystone.common import driver_hints
-from keystone.common import kvs
-
-
-class Catalog(kvs.Base, catalog.CatalogDriverV8):
-    # Public interface
-    def get_catalog(self, user_id, tenant_id):
-        return self.db.get('catalog-%s-%s' % (tenant_id, user_id))
-
-    # region crud
-
-    def _delete_child_regions(self, region_id, root_region_id):
-        """Delete all child regions.
-
-        Recursively delete any region that has the supplied region
-        as its parent.
-        """
-        children = [r for r in self.list_regions(driver_hints.Hints())
-                    if r['parent_region_id'] == region_id]
-        for child in children:
-            if child['id'] == root_region_id:
-                # Hit a circular region hierarchy
-                return
-            self._delete_child_regions(child['id'], root_region_id)
-            self._delete_region(child['id'])
-
-    def _check_parent_region(self, region_ref):
-        """Raise a NotFound if the parent region does not exist.
-
-        If the region_ref has a specified parent_region_id, check that
-        the parent exists, otherwise, raise a NotFound.
-        """
-        parent_region_id = region_ref.get('parent_region_id')
-        if parent_region_id is not None:
-            # This will raise NotFound if the parent doesn't exist,
-            # which is the behavior we want.
-            self.get_region(parent_region_id)
-
-    def create_region(self, region):
-        region_id = region['id']
-        region.setdefault('parent_region_id')
-        self._check_parent_region(region)
-        self.db.set('region-%s' % region_id, region)
-        region_list = set(self.db.get('region_list', []))
-        region_list.add(region_id)
-        self.db.set('region_list', list(region_list))
-        return region
-
-    def list_regions(self, hints):
-        return [self.get_region(x) for x in self.db.get('region_list', [])]
-
-    def get_region(self, region_id):
-        return self.db.get('region-%s' % region_id)
-
-    def update_region(self, region_id, region):
-        self._check_parent_region(region)
-        old_region = self.get_region(region_id)
-        old_region.update(region)
-        self._ensure_no_circle_in_hierarchical_regions(old_region)
-        self.db.set('region-%s' % region_id, old_region)
-        return old_region
-
-    def _delete_region(self, region_id):
-        self.db.delete('region-%s' % region_id)
-        region_list = set(self.db.get('region_list', []))
-        region_list.remove(region_id)
-        self.db.set('region_list', list(region_list))
-
-    def delete_region(self, region_id):
-        self._delete_child_regions(region_id, region_id)
-        self._delete_region(region_id)
-
-    # service crud
-
-    def create_service(self, service_id, service):
-        self.db.set('service-%s' % service_id, service)
-        service_list = set(self.db.get('service_list', []))
-        service_list.add(service_id)
-        self.db.set('service_list', list(service_list))
-        return service
-
-    def list_services(self, hints):
-        return [self.get_service(x) for x in self.db.get('service_list', [])]
-
-    def get_service(self, service_id):
-        return self.db.get('service-%s' % service_id)
-
-    def update_service(self, service_id, service):
-        old_service = self.get_service(service_id)
-        old_service.update(service)
-        self.db.set('service-%s' % service_id, old_service)
-        return old_service
-
-    def delete_service(self, service_id):
-        # delete referencing endpoints
-        for endpoint_id in self.db.get('endpoint_list', []):
-            if self.get_endpoint(endpoint_id)['service_id'] == service_id:
-                self.delete_endpoint(endpoint_id)
-
-        self.db.delete('service-%s' % service_id)
-        service_list = set(self.db.get('service_list', []))
-        service_list.remove(service_id)
-        self.db.set('service_list', list(service_list))
-
-    # endpoint crud
-
-    def create_endpoint(self, endpoint_id, endpoint):
-        self.db.set('endpoint-%s' % endpoint_id, endpoint)
-        endpoint_list = set(self.db.get('endpoint_list', []))
-        endpoint_list.add(endpoint_id)
-        self.db.set('endpoint_list', list(endpoint_list))
-        return endpoint
-
-    def list_endpoints(self, hints):
-        return [self.get_endpoint(x) for x in self.db.get('endpoint_list', [])]
-
-    def get_endpoint(self, endpoint_id):
-        return self.db.get('endpoint-%s' % endpoint_id)
-
-    def update_endpoint(self, endpoint_id, endpoint):
-        if endpoint.get('region_id') is not None:
-            self.get_region(endpoint['region_id'])
-
-        old_endpoint = self.get_endpoint(endpoint_id)
-        old_endpoint.update(endpoint)
-        self.db.set('endpoint-%s' % endpoint_id, old_endpoint)
-        return old_endpoint
-
-    def delete_endpoint(self, endpoint_id):
-        self.db.delete('endpoint-%s' % endpoint_id)
-        endpoint_list = set(self.db.get('endpoint_list', []))
-        endpoint_list.remove(endpoint_id)
-        self.db.set('endpoint_list', list(endpoint_list))
-
-    # Private interface
-    def _create_catalog(self, user_id, tenant_id, data):
-        self.db.set('catalog-%s-%s' % (tenant_id, user_id), data)
-        return data
-
-    # TODO(davechen): Apparently, these methods are not implemented but
-    # we cannot raise exception.NotImplemented() just because the notification
-    # to those resource will break some testcases, will look into CADF to
-    # see if there is any better way to do this.
-    def add_endpoint_to_project(self, endpoint_id, project_id):
-        """Create an endpoint to project association.
-
-        :param endpoint_id: identity of endpoint to associate
-        :type endpoint_id: string
-        :param project_id: identity of the project to be associated with
-        :type project_id: string
-        :raises: keystone.exception.Conflict: If the endpoint was already
-            added to project.
-        :returns: None.
-
-        """
-        pass
-
-    def remove_endpoint_from_project(self, endpoint_id, project_id):
-        """Removes an endpoint to project association.
-
-        :param endpoint_id: identity of endpoint to remove
-        :type endpoint_id: string
-        :param project_id: identity of the project associated with
-        :type project_id: string
-        :raises keystone.exception.NotFound: If the endpoint was not found
-            in the project.
-        :returns: None.
-
-        """
-        pass
-
-    def check_endpoint_in_project(self, endpoint_id, project_id):
-        """Checks if an endpoint is associated with a project.
-
-        :param endpoint_id: identity of endpoint to check
-        :type endpoint_id: string
-        :param project_id: identity of the project associated with
-        :type project_id: string
-        :raises keystone.exception.NotFound: If the endpoint was not found
-            in the project.
-        :returns: None.
-
-        """
-        pass
-
-    def list_endpoints_for_project(self, project_id):
-        """List all endpoints associated with a project.
-
-        :param project_id: identity of the project to check
-        :type project_id: string
-        :returns: a list of identity endpoint ids or an empty list.
-
-        """
-        pass
-
-    def list_projects_for_endpoint(self, endpoint_id):
-        """List all projects associated with an endpoint.
-
-        :param endpoint_id: identity of endpoint to check
-        :type endpoint_id: string
-        :returns: a list of projects or an empty list.
-
-        """
-        pass
-
-    def delete_association_by_endpoint(self, endpoint_id):
-        """Removes all the endpoints to project association with endpoint.
-
-        :param endpoint_id: identity of endpoint to check
-        :type endpoint_id: string
-        :returns: None
-
-        """
-        pass
-
-    def delete_association_by_project(self, project_id):
-        """Removes all the endpoints to project association with project.
-
-        :param project_id: identity of the project to check
-        :type project_id: string
-        :returns: None
-
-        """
-        pass
-
-    def create_endpoint_group(self, endpoint_group):
-        """Create an endpoint group.
-
-        :param endpoint_group: endpoint group to create
-        :type endpoint_group: dictionary
-        :raises: keystone.exception.Conflict: If a duplicate endpoint group
-            already exists.
-        :returns: an endpoint group representation.
-
-        """
-        pass
-
-    def get_endpoint_group(self, endpoint_group_id):
-        """Get an endpoint group.
-
-        :param endpoint_group_id: identity of endpoint group to retrieve
-        :type endpoint_group_id: string
-        :raises keystone.exception.NotFound: If the endpoint group was not
-            found.
-        :returns: an endpoint group representation.
-
-        """
-        pass
-
-    def update_endpoint_group(self, endpoint_group_id, endpoint_group):
-        """Update an endpoint group.
-
-        :param endpoint_group_id: identity of endpoint group to retrieve
-        :type endpoint_group_id: string
-        :param endpoint_group: A full or partial endpoint_group
-        :type endpoint_group: dictionary
-        :raises keystone.exception.NotFound: If the endpoint group was not
-            found.
-        :returns: an endpoint group representation.
-
-        """
-        pass
-
-    def delete_endpoint_group(self, endpoint_group_id):
-        """Delete an endpoint group.
-
-        :param endpoint_group_id: identity of endpoint group to delete
-        :type endpoint_group_id: string
-        :raises keystone.exception.NotFound: If the endpoint group was not
-            found.
-        :returns: None.
-
-        """
-        pass
-
-    def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
-        """Adds an endpoint group to project association.
-
-        :param endpoint_group_id: identity of endpoint to associate
-        :type endpoint_group_id: string
-        :param project_id: identity of project to associate
-        :type project_id: string
-        :raises keystone.exception.Conflict: If the endpoint group was already
-            added to the project.
-        :returns: None.
-
-        """
-        pass
-
-    def get_endpoint_group_in_project(self, endpoint_group_id, project_id):
-        """Get endpoint group to project association.
-
-        :param endpoint_group_id: identity of endpoint group to retrieve
-        :type endpoint_group_id: string
-        :param project_id: identity of project to associate
-        :type project_id: string
-        :raises keystone.exception.NotFound: If the endpoint group to the
-            project association was not found.
-        :returns: a project endpoint group representation.
-
-        """
-        pass
-
-    def list_endpoint_groups(self):
-        """List all endpoint groups.
-
-        :returns: None.
-
-        """
-        pass
-
-    def list_endpoint_groups_for_project(self, project_id):
-        """List all endpoint group to project associations for a project.
-
-        :param project_id: identity of project to associate
-        :type project_id: string
-        :returns: None.
-
-        """
-        pass
-
-    def list_projects_associated_with_endpoint_group(self, endpoint_group_id):
-        """List all projects associated with endpoint group.
-
-        :param endpoint_group_id: identity of endpoint to associate
-        :type endpoint_group_id: string
-        :returns: None.
-
-        """
-        pass
-
-    def remove_endpoint_group_from_project(self, endpoint_group_id,
-                                           project_id):
-        """Remove an endpoint to project association.
-
-        :param endpoint_group_id: identity of endpoint to associate
-        :type endpoint_group_id: string
-        :param project_id: identity of project to associate
-        :type project_id: string
-        :raises keystone.exception.NotFound: If endpoint group project
-            association was not found.
-        :returns: None.
-
-        """
-        pass
-
-    def delete_endpoint_group_association_by_project(self, project_id):
-        """Remove endpoint group to project associations.
-
-        :param project_id: identity of the project to check
-        :type project_id: string
-        :returns: None
-
-        """
-        pass
diff --git a/keystone/catalog/backends/templated.py b/keystone/catalog/backends/templated.py
index 4e667f7407..0f28d608d7 100644
--- a/keystone/catalog/backends/templated.py
+++ b/keystone/catalog/backends/templated.py
@@ -17,8 +17,8 @@ import os.path
 
 from oslo_config import cfg
 from oslo_log import log
+import six
 
-from keystone.catalog.backends import kvs
 from keystone.catalog import core
 from keystone import exception
 from keystone.i18n import _LC
@@ -56,7 +56,7 @@ def parse_templates(template_lines):
     return o
 
 
-class Catalog(kvs.Catalog):
+class Catalog(core.Driver):
     """A backend that generates endpoints for the Catalog based on templates.
 
     It is usually configured via config entries that look like:
@@ -105,6 +105,95 @@ class Catalog(kvs.Catalog):
             LOG.critical(_LC('Unable to open template file %s'), template_file)
             raise
 
+    # region crud
+
+    def create_region(self, region_ref):
+        raise exception.NotImplemented()
+
+    def list_regions(self, hints):
+        return [{'id': region_id, 'description': '', 'parent_region_id': ''}
+                for region_id in self.templates]
+
+    def get_region(self, region_id):
+        if region_id in self.templates:
+            return {'id': region_id, 'description': '', 'parent_region_id': ''}
+        raise exception.RegionNotFound(region_id=region_id)
+
+    def update_region(self, region_id, region_ref):
+        raise exception.NotImplemented()
+
+    def delete_region(self, region_id):
+        raise exception.NotImplemented()
+
+    # service crud
+
+    def create_service(self, service_id, service_ref):
+        raise exception.NotImplemented()
+
+    def _list_services(self, hints):
+        for region_ref in six.itervalues(self.templates):
+            for service_type, service_ref in six.iteritems(region_ref):
+                yield {
+                    'id': service_type,
+                    'enabled': True,
+                    'name': service_ref.get('name', ''),
+                    'description': service_ref.get('description', ''),
+                    'type': service_type,
+                }
+
+    def list_services(self, hints):
+        return list(self._list_services())
+
+    def get_service(self, service_id):
+        for service in self._list_services(hints=None):
+            if service['id'] == service_id:
+                return service
+        raise exception.ServiceNotFound(service_id=service_id)
+
+    def update_service(self, service_id, service_ref):
+        raise exception.NotImplemented()
+
+    def delete_service(self, service_id):
+        raise exception.NotImplemented()
+
+    # endpoint crud
+
+    def create_endpoint(self, endpoint_id, endpoint_ref):
+        raise exception.NotImplemented()
+
+    def _list_endpoints(self):
+        for region_id, region_ref in six.iteritems(self.templates):
+            for service_type, service_ref in six.iteritems(region_ref):
+                for key in service_ref:
+                    if key.endswith('URL'):
+                        interface = key[:-3]
+                        endpoint_id = ('%s-%s-%s' %
+                                       (region_id, service_type, interface))
+                        yield {
+                            'id': endpoint_id,
+                            'service_id': service_type,
+                            'interface': interface,
+                            'url': service_ref[key],
+                            'legacy_endpoint_id': None,
+                            'region_id': region_id,
+                            'enabled': True,
+                        }
+
+    def list_endpoints(self, hints):
+        return list(self._list_endpoints())
+
+    def get_endpoint(self, endpoint_id):
+        for endpoint in self._list_endpoints():
+            if endpoint['id'] == endpoint_id:
+                return endpoint
+        raise exception.EndpointNotFound(endpoint_id=endpoint_id)
+
+    def update_endpoint(self, endpoint_id, endpoint_ref):
+        raise exception.NotImplemented()
+
+    def delete_endpoint(self, endpoint_id):
+        raise exception.NotImplemented()
+
     def get_catalog(self, user_id, tenant_id):
         """Retrieve and format the V2 service catalog.
 
@@ -148,3 +237,58 @@ class Catalog(kvs.Catalog):
                 catalog[region][service] = service_data
 
         return catalog
+
+    def add_endpoint_to_project(self, endpoint_id, project_id):
+        raise exception.NotImplemented()
+
+    def remove_endpoint_from_project(self, endpoint_id, project_id):
+        raise exception.NotImplemented()
+
+    def check_endpoint_in_project(self, endpoint_id, project_id):
+        raise exception.NotImplemented()
+
+    def list_endpoints_for_project(self, project_id):
+        raise exception.NotImplemented()
+
+    def list_projects_for_endpoint(self, endpoint_id):
+        raise exception.NotImplemented()
+
+    def delete_association_by_endpoint(self, endpoint_id):
+        raise exception.NotImplemented()
+
+    def delete_association_by_project(self, project_id):
+        raise exception.NotImplemented()
+
+    def create_endpoint_group(self, endpoint_group):
+        raise exception.NotImplemented()
+
+    def get_endpoint_group(self, endpoint_group_id):
+        raise exception.NotImplemented()
+
+    def update_endpoint_group(self, endpoint_group_id, endpoint_group):
+        raise exception.NotImplemented()
+
+    def delete_endpoint_group(self, endpoint_group_id):
+        raise exception.NotImplemented()
+
+    def add_endpoint_group_to_project(self, endpoint_group_id, project_id):
+        raise exception.NotImplemented()
+
+    def get_endpoint_group_in_project(self, endpoint_group_id, project_id):
+        raise exception.NotImplemented()
+
+    def list_endpoint_groups(self):
+        raise exception.NotImplemented()
+
+    def list_endpoint_groups_for_project(self, project_id):
+        raise exception.NotImplemented()
+
+    def list_projects_associated_with_endpoint_group(self, endpoint_group_id):
+        raise exception.NotImplemented()
+
+    def remove_endpoint_group_from_project(self, endpoint_group_id,
+                                           project_id):
+        raise exception.NotImplemented()
+
+    def delete_endpoint_group_association_by_project(self, project_id):
+        raise exception.NotImplemented()
diff --git a/keystone/common/kvs/__init__.py b/keystone/common/kvs/__init__.py
index 9a406a85bd..354bbd8ad8 100644
--- a/keystone/common/kvs/__init__.py
+++ b/keystone/common/kvs/__init__.py
@@ -15,7 +15,6 @@
 from dogpile.cache import region
 
 from keystone.common.kvs.core import *  # noqa
-from keystone.common.kvs.legacy import Base, DictKvs, INMEMDB  # noqa
 
 
 # NOTE(morganfainberg): Provided backends are registered here in the __init__
diff --git a/keystone/common/kvs/legacy.py b/keystone/common/kvs/legacy.py
deleted file mode 100644
index 7e27d97fbb..0000000000
--- a/keystone/common/kvs/legacy.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from oslo_log import versionutils
-
-from keystone import exception
-
-
-class DictKvs(dict):
-    def get(self, key, default=None):
-        try:
-            if isinstance(self[key], dict):
-                return self[key].copy()
-            else:
-                return self[key][:]
-        except KeyError:
-            if default is not None:
-                return default
-            raise exception.NotFound(target=key)
-
-    def set(self, key, value):
-        if isinstance(value, dict):
-            self[key] = value.copy()
-        else:
-            self[key] = value[:]
-
-    def delete(self, key):
-        """Deletes an item, returning True on success, False otherwise."""
-        try:
-            del self[key]
-        except KeyError:
-            raise exception.NotFound(target=key)
-
-
-INMEMDB = DictKvs()
-
-
-class Base(object):
-    @versionutils.deprecated(versionutils.deprecated.ICEHOUSE,
-                             in_favor_of='keystone.common.kvs.KeyValueStore',
-                             remove_in=+2,
-                             what='keystone.common.kvs.Base')
-    def __init__(self, db=None):
-        if db is None:
-            db = INMEMDB
-        elif isinstance(db, DictKvs):
-            db = db
-        elif isinstance(db, dict):
-            db = DictKvs(db)
-        self.db = db
diff --git a/keystone/tests/unit/core.py b/keystone/tests/unit/core.py
index f90874a296..9d955d2f28 100644
--- a/keystone/tests/unit/core.py
+++ b/keystone/tests/unit/core.py
@@ -49,7 +49,6 @@ environment.use_eventlet()
 from keystone import auth
 from keystone.common import config
 from keystone.common import dependency
-from keystone.common import kvs
 from keystone.common.kvs import core as kvs_core
 from keystone.common import sql
 from keystone import exception
@@ -534,7 +533,7 @@ class TestCase(BaseTestCase):
             proxies=['oslo_cache.testing.CacheIsolatingProxy'])
         self.config_fixture.config(
             group='catalog',
-            driver='templated',
+            driver='sql',
             template_file=dirs.tests('default_catalog.templates'))
         self.config_fixture.config(
             group='kvs',
@@ -619,8 +618,6 @@ class TestCase(BaseTestCase):
         # tests aren't used.
         self.addCleanup(dependency.reset)
 
-        self.addCleanup(kvs.INMEMDB.clear)
-
         # Ensure Notification subscriptions and resource types are empty
         self.addCleanup(notifications.clear_subscribers)
         self.addCleanup(notifications.reset_notifier)
diff --git a/keystone/tests/unit/test_backend.py b/keystone/tests/unit/test_backend.py
index 7f720cd055..feb205d520 100644
--- a/keystone/tests/unit/test_backend.py
+++ b/keystone/tests/unit/test_backend.py
@@ -4801,7 +4801,7 @@ class TrustTests(object):
 
 class CatalogTests(object):
 
-    _legacy_endpoint_id_in_endpoint = False
+    _legacy_endpoint_id_in_endpoint = True
     _enabled_default_to_true_when_creating_endpoint = False
 
     def test_region_crud(self):
@@ -5261,6 +5261,7 @@ class CatalogTests(object):
         res = self.catalog_api.update_endpoint(endpoint_ref['id'],
                                                {'interface': 'private'})
         expected_endpoint = endpoint_ref.copy()
+        expected_endpoint['enabled'] = True
         expected_endpoint['interface'] = 'private'
         if self._legacy_endpoint_id_in_endpoint:
             expected_endpoint['legacy_endpoint_id'] = None
diff --git a/keystone/tests/unit/test_backend_kvs.py b/keystone/tests/unit/test_backend_kvs.py
index 1fbbcd48b4..d29ebab662 100644
--- a/keystone/tests/unit/test_backend_kvs.py
+++ b/keystone/tests/unit/test_backend_kvs.py
@@ -103,60 +103,6 @@ class KvsToken(unit.TestCase, test_backend.TokenTests):
         self.assertEqual(expected_user_token_list, user_token_list)
 
 
-class KvsCatalog(unit.TestCase, test_backend.CatalogTests):
-    def setUp(self):
-        super(KvsCatalog, self).setUp()
-        self.load_backends()
-        self._load_fake_catalog()
-
-    def config_overrides(self):
-        super(KvsCatalog, self).config_overrides()
-        self.config_fixture.config(group='catalog', driver='kvs')
-
-    def _load_fake_catalog(self):
-        self.catalog_foobar = self.catalog_api.driver._create_catalog(
-            'foo', 'bar',
-            {'RegionFoo': {'service_bar': {'foo': 'bar'}}})
-
-    def test_get_catalog_returns_not_found(self):
-        # FIXME(dolph): this test should be moved up to test_backend
-        # FIXME(dolph): exceptions should be UserNotFound and ProjectNotFound
-        self.assertRaises(exception.NotFound,
-                          self.catalog_api.get_catalog,
-                          uuid.uuid4().hex,
-                          'bar')
-
-        self.assertRaises(exception.NotFound,
-                          self.catalog_api.get_catalog,
-                          'foo',
-                          uuid.uuid4().hex)
-
-    def test_get_catalog(self):
-        catalog_ref = self.catalog_api.get_catalog('foo', 'bar')
-        self.assertDictEqual(self.catalog_foobar, catalog_ref)
-
-    def test_get_catalog_endpoint_disabled(self):
-        # This test doesn't apply to KVS because with the KVS backend the
-        # application creates the catalog (including the endpoints) for each
-        # user and project. Whether endpoints are enabled or disabled isn't
-        # a consideration.
-        f = super(KvsCatalog, self).test_get_catalog_endpoint_disabled
-        self.assertRaises(exception.NotFound, f)
-
-    def test_get_v3_catalog_endpoint_disabled(self):
-        # There's no need to have disabled endpoints in the kvs catalog. Those
-        # endpoints should just be removed from the store. This just tests
-        # what happens currently when the super impl is called.
-        f = super(KvsCatalog, self).test_get_v3_catalog_endpoint_disabled
-        self.assertRaises(exception.NotFound, f)
-
-    def test_list_regions_filtered_by_parent_region_id(self):
-        self.skipTest('KVS backend does not support hints')
-
-    def test_service_filtering(self):
-        self.skipTest("kvs backend doesn't support filtering")
-
-
 class KvsTokenCacheInvalidation(unit.TestCase,
                                 test_backend.TokenCacheInvalidation):
     def setUp(self):
diff --git a/keystone/tests/unit/test_backend_templated.py b/keystone/tests/unit/test_backend_templated.py
index f65c6d472d..7e69fd07f0 100644
--- a/keystone/tests/unit/test_backend_templated.py
+++ b/keystone/tests/unit/test_backend_templated.py
@@ -232,11 +232,11 @@ class TestTemplatedCatalog(unit.TestCase, test_backend.CatalogTests):
         self.skipTest(BROKEN_WRITE_FUNCTIONALITY_MSG)
 
     def test_list_endpoints(self):
-        # NOTE(dstanek): a future commit will fix this functionality and
-        # this test
-        expected_ids = set()
+        expected_urls = set(['http://localhost:$(public_port)s/v2.0',
+                             'http://localhost:$(admin_port)s/v2.0',
+                             'http://localhost:8774/v1.1/$(tenant_id)s'])
         endpoints = self.catalog_api.list_endpoints()
-        self.assertEqual(expected_ids, set(e['id'] for e in endpoints))
+        self.assertEqual(expected_urls, set(e['url'] for e in endpoints))
 
     @unit.skip_if_cache_disabled('catalog')
     def test_invalidate_cache_when_updating_endpoint(self):
diff --git a/keystone/tests/unit/test_v2.py b/keystone/tests/unit/test_v2.py
index da85b25dce..ff5175ff23 100644
--- a/keystone/tests/unit/test_v2.py
+++ b/keystone/tests/unit/test_v2.py
@@ -23,6 +23,7 @@ from six.moves import http_client
 from testtools import matchers
 
 from keystone.common import extension as keystone_extension
+from keystone.tests import unit
 from keystone.tests.unit import ksfixtures
 from keystone.tests.unit import rest
 
@@ -987,6 +988,14 @@ class RestfulTestCase(rest.RestfulTestCase):
 
 
 class V2TestCase(RestfulTestCase, CoreApiTests, LegacyV2UsernameTests):
+
+    def config_overrides(self):
+        super(V2TestCase, self).config_overrides()
+        self.config_fixture.config(
+            group='catalog',
+            driver='templated',
+            template_file=unit.dirs.tests('default_catalog.templates'))
+
     def _get_user_id(self, r):
         return r['user']['id']
 
diff --git a/releasenotes/notes/impl-templated-catalog-1d8f6333726b34f8.yaml b/releasenotes/notes/impl-templated-catalog-1d8f6333726b34f8.yaml
new file mode 100644
index 0000000000..3afd9159a1
--- /dev/null
+++ b/releasenotes/notes/impl-templated-catalog-1d8f6333726b34f8.yaml
@@ -0,0 +1,9 @@
+---
+other:
+  - >
+    [`bug 1367113 <https://bugs.launchpad.net/keystone/+bug/1367113>`_]
+    The "get entity" and "list entities" functionality for the KVS catalog
+    backend has been reimplemented to use the data from the catalog template.
+    Previously this would only act on temporary data that was created at
+    runtime. The create, update and delete entity functionality now raises
+    an exception.
diff --git a/releasenotes/notes/removed-as-of-mitaka-9ff14f87d0b98e7e.yaml b/releasenotes/notes/removed-as-of-mitaka-9ff14f87d0b98e7e.yaml
index 2afa8ce399..de383f01ec 100644
--- a/releasenotes/notes/removed-as-of-mitaka-9ff14f87d0b98e7e.yaml
+++ b/releasenotes/notes/removed-as-of-mitaka-9ff14f87d0b98e7e.yaml
@@ -22,3 +22,7 @@ other:
     Removed ``check_role_for_trust`` from the trust controller, ensure policy
     files do not refer to this target. This was deprecated in the Kilo
     release.
+  - >
+    [`blueprint removed-as-of-mitaka <https://blueprints.launchpad.net/keystone/+spec/removed-as-of-mitaka>`_]
+    Removed Catalog KVS backend (``keystone.catalog.backends.sql.Catalog``).
+    This was deprecated in the Icehouse release.
diff --git a/setup.cfg b/setup.cfg
index 210f13a790..a5c1cf1188 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -106,7 +106,6 @@ keystone.auth.x509 =
     default = keystone.auth.plugins.mapped:Mapped
 
 keystone.catalog =
-    kvs = keystone.catalog.backends.kvs:Catalog
     sql = keystone.catalog.backends.sql:Catalog
     templated = keystone.catalog.backends.templated:Catalog
     endpoint_filter.sql = keystone.contrib.endpoint_filter.backends.catalog_sql:EndpointFilterCatalog