diff --git a/django/contrib/gis/db/backends/spatialite/compiler.py b/django/contrib/gis/db/backends/spatialite/compiler.py
deleted file mode 100644
--- a/django/contrib/gis/db/backends/spatialite/compiler.py
+++ /dev/null
@@ -1,32 +0,0 @@
-from django.db.backends.util import typecast_timestamp
-from django.db.models.sql import compiler
-from django.db.models.sql.constants import MULTI
-from django.contrib.gis.db.models.sql.compiler import GeoSQLCompiler as BaseGeoSQLCompiler
-
-SQLCompiler = compiler.SQLCompiler
-
-class GeoSQLCompiler(BaseGeoSQLCompiler, SQLCompiler):
-    pass
-
-class SQLInsertCompiler(compiler.SQLInsertCompiler, GeoSQLCompiler):
-    pass
-
-class SQLDeleteCompiler(compiler.SQLDeleteCompiler, GeoSQLCompiler):
-    pass
-
-class SQLUpdateCompiler(compiler.SQLUpdateCompiler, GeoSQLCompiler):
-    pass
-
-class SQLAggregateCompiler(compiler.SQLAggregateCompiler, GeoSQLCompiler):
-    pass
-
-class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler):
-    """
-    This is overridden for GeoDjango to properly cast date columns, see #16757.
-    """
-    def results_iter(self):
-        offset = len(self.query.extra_select)
-        for rows in self.execute_sql(MULTI):
-            for row in rows:
-                date = typecast_timestamp(str(row[offset]))
-                yield date
diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py
--- a/django/contrib/gis/db/backends/spatialite/operations.py
+++ b/django/contrib/gis/db/backends/spatialite/operations.py
@@ -48,7 +48,7 @@
     return (SpatiaLiteDistance(operator),)
 
 class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations):
-    compiler_module = 'django.contrib.gis.db.backends.spatialite.compiler'
+    compiler_module = 'django.contrib.gis.db.models.sql.compiler'
     name = 'spatialite'
     spatialite = True
     version_regex = re.compile(r'^(?P<major>\d)\.(?P<minor1>\d)\.(?P<minor2>\d+)')
diff --git a/django/contrib/gis/db/models/sql/compiler.py b/django/contrib/gis/db/models/sql/compiler.py
--- a/django/contrib/gis/db/models/sql/compiler.py
+++ b/django/contrib/gis/db/models/sql/compiler.py
@@ -1,7 +1,7 @@
 from itertools import izip
-from django.db.backends.util import truncate_name
+from django.db.backends.util import truncate_name, typecast_timestamp
 from django.db.models.sql import compiler
-from django.db.models.sql.constants import TABLE_NAME
+from django.db.models.sql.constants import TABLE_NAME, MULTI
 from django.db.models.sql.query import get_proxied_model
 
 SQLCompiler = compiler.SQLCompiler
@@ -194,7 +194,7 @@
             # We resolve the rest of the columns if we're on Oracle or if
             # the `geo_values` attribute is defined.
             for value, field in map(None, row[index_start:], fields):
-                values.append(self.query.convert_values(value, field, connection=self.connection))
+                values.append(self.query.convert_values(value, field, self.connection))
         else:
             values.extend(row[index_start:])
         return tuple(values)
@@ -275,4 +275,24 @@
     pass
 
 class SQLDateCompiler(compiler.SQLDateCompiler, GeoSQLCompiler):
-    pass
+    """
+    This is overridden for GeoDjango to properly cast date columns, since
+    `GeoQuery.resolve_columns` is used for spatial values.
+    See #14648, #16757.
+    """
+    def results_iter(self):
+        if self.connection.ops.oracle:
+            from django.db.models.fields import DateTimeField
+            fields = [DateTimeField()]
+        else:
+            needs_string_cast = self.connection.features.needs_datetime_string_cast
+
+        offset = len(self.query.extra_select)
+        for rows in self.execute_sql(MULTI):
+            for row in rows:
+                date = row[offset]
+                if self.connection.ops.oracle:
+                    date = self.resolve_columns(row, fields)[offset]
+                elif needs_string_cast:
+                    date = typecast_timestamp(str(date))
+                yield date
diff --git a/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz b/django/contrib/gis/tests/relatedapp/fixtures/initial_data.json.gz
index 68bf54c1b0d196a4e3b35d1b9045a6d8bf3f416e..893763724b819f615c09dd01e1b5705f5352d4c6
GIT binary patch
diff --git a/django/contrib/gis/tests/relatedapp/models.py b/django/contrib/gis/tests/relatedapp/models.py
--- a/django/contrib/gis/tests/relatedapp/models.py
+++ b/django/contrib/gis/tests/relatedapp/models.py
@@ -36,6 +36,7 @@
 # These use the GeoManager but do not have any geographic fields.
 class Author(models.Model):
     name = models.CharField(max_length=100)
+    dob = models.DateField()
     objects = models.GeoManager()
 
 class Article(models.Model):
diff --git a/django/contrib/gis/tests/relatedapp/tests.py b/django/contrib/gis/tests/relatedapp/tests.py
--- a/django/contrib/gis/tests/relatedapp/tests.py
+++ b/django/contrib/gis/tests/relatedapp/tests.py
@@ -1,3 +1,4 @@
+from datetime import date
 from django.test import TestCase
 
 from django.contrib.gis.geos import GEOSGeometry, Point, MultiPoint
@@ -281,4 +282,11 @@
         # evaluated as list generation swallows TypeError in CPython.
         sql = str(qs.query)
 
+    def test16_annotated_date_queryset(self):
+        "Ensure annotated date querysets work if spatial backend is used.  See #14648."
+        birth_years = [dt.year for dt in 
+                       list(Author.objects.annotate(num_books=Count('books')).dates('dob', 'year'))]
+        birth_years.sort()
+        self.assertEqual([1950, 1974], birth_years)
+
     # TODO: Related tests for KML, GML, and distance lookups.
