diff --git a/django/contrib/gis/geos/collections.py b/django/contrib/gis/geos/collections.py
index becc6b0ce3..01277b1b65 100644
--- a/django/contrib/gis/geos/collections.py
+++ b/django/contrib/gis/geos/collections.py
@@ -7,10 +7,9 @@ import warnings
 from ctypes import byref, c_int, c_uint
 
 from django.contrib.gis.geos import prototypes as capi
-from django.contrib.gis.geos.geometry import (
-    GEOSGeometry, ProjectInterpolateMixin,
-)
-from django.contrib.gis.geos.libgeos import get_pointer_arr
+from django.contrib.gis.geos.error import GEOSException
+from django.contrib.gis.geos.geometry import GEOSGeometry, LinearGeometryMixin
+from django.contrib.gis.geos.libgeos import geos_version_info, get_pointer_arr
 from django.contrib.gis.geos.linestring import LinearRing, LineString
 from django.contrib.gis.geos.point import Point
 from django.contrib.gis.geos.polygon import Polygon
@@ -114,17 +113,15 @@ class MultiPoint(GeometryCollection):
     _typeid = 4
 
 
-class MultiLineString(ProjectInterpolateMixin, GeometryCollection):
+class MultiLineString(LinearGeometryMixin, GeometryCollection):
     _allowed = (LineString, LinearRing)
     _typeid = 5
 
     @property
-    def merged(self):
-        """
-        Returns a LineString representing the line merge of this
-        MultiLineString.
-        """
-        return self._topology(capi.geos_linemerge(self.ptr))
+    def closed(self):
+        if geos_version_info()['version'] < '3.5':
+            raise GEOSException("MultiLineString.closed requires GEOS >= 3.5.0.")
+        return super(MultiLineString, self).closed
 
 
 class MultiPolygon(GeometryCollection):
diff --git a/django/contrib/gis/geos/geometry.py b/django/contrib/gis/geos/geometry.py
index 1aea19821d..f66effd756 100644
--- a/django/contrib/gis/geos/geometry.py
+++ b/django/contrib/gis/geos/geometry.py
@@ -685,7 +685,7 @@ class GEOSGeometry(GEOSBase, ListMixin):
         return GEOSGeometry(capi.geom_clone(self.ptr), srid=self.srid)
 
 
-class ProjectInterpolateMixin(object):
+class LinearGeometryMixin(object):
     """
     Used for LineString and MultiLineString.
     """
@@ -706,3 +706,17 @@ class ProjectInterpolateMixin(object):
         if not isinstance(point, Point):
             raise TypeError('locate_point argument must be a Point')
         return capi.geos_project_normalized(self.ptr, point.ptr)
+
+    @property
+    def merged(self):
+        """
+        Return the line merge of this Geometry.
+        """
+        return self._topology(capi.geos_linemerge(self.ptr))
+
+    @property
+    def closed(self):
+        """
+        Return whether or not this Geometry is closed.
+        """
+        return capi.geos_isclosed(self.ptr)
diff --git a/django/contrib/gis/geos/linestring.py b/django/contrib/gis/geos/linestring.py
index cf74aad7fa..7bfc004370 100644
--- a/django/contrib/gis/geos/linestring.py
+++ b/django/contrib/gis/geos/linestring.py
@@ -1,15 +1,13 @@
 from django.contrib.gis.geos import prototypes as capi
 from django.contrib.gis.geos.coordseq import GEOSCoordSeq
 from django.contrib.gis.geos.error import GEOSException
-from django.contrib.gis.geos.geometry import (
-    GEOSGeometry, ProjectInterpolateMixin,
-)
+from django.contrib.gis.geos.geometry import GEOSGeometry, LinearGeometryMixin
 from django.contrib.gis.geos.point import Point
 from django.contrib.gis.shortcuts import numpy
 from django.utils.six.moves import range
 
 
-class LineString(ProjectInterpolateMixin, GEOSGeometry):
+class LineString(LinearGeometryMixin, GEOSGeometry):
     _init_func = capi.create_linestring
     _minlength = 2
     has_cs = True
@@ -154,11 +152,6 @@ class LineString(ProjectInterpolateMixin, GEOSGeometry):
         "Returns a numpy array for the LineString."
         return self._listarr(self._cs.__getitem__)
 
-    @property
-    def merged(self):
-        "Returns the line merge of this LineString."
-        return self._topology(capi.geos_linemerge(self.ptr))
-
     @property
     def x(self):
         "Returns a list or numpy array of the X variable."
diff --git a/django/contrib/gis/geos/prototypes/__init__.py b/django/contrib/gis/geos/prototypes/__init__.py
index 32073749d8..0357b8110e 100644
--- a/django/contrib/gis/geos/prototypes/__init__.py
+++ b/django/contrib/gis/geos/prototypes/__init__.py
@@ -19,8 +19,8 @@ from django.contrib.gis.geos.prototypes.geom import (  # NOQA
 from django.contrib.gis.geos.prototypes.misc import *  # NOQA
 from django.contrib.gis.geos.prototypes.predicates import (  # NOQA
     geos_contains, geos_covers, geos_crosses, geos_disjoint, geos_equals,
-    geos_equalsexact, geos_hasz, geos_intersects, geos_isempty, geos_isring,
-    geos_issimple, geos_isvalid, geos_overlaps, geos_relatepattern,
-    geos_touches, geos_within,
+    geos_equalsexact, geos_hasz, geos_intersects, geos_isclosed, geos_isempty,
+    geos_isring, geos_issimple, geos_isvalid, geos_overlaps,
+    geos_relatepattern, geos_touches, geos_within,
 )
 from django.contrib.gis.geos.prototypes.topology import *  # NOQA
diff --git a/django/contrib/gis/geos/prototypes/predicates.py b/django/contrib/gis/geos/prototypes/predicates.py
index 8d335fa187..9021fc71f3 100644
--- a/django/contrib/gis/geos/prototypes/predicates.py
+++ b/django/contrib/gis/geos/prototypes/predicates.py
@@ -23,6 +23,7 @@ class BinaryPredicate(UnaryPredicate):
 
 # ## Unary Predicates ##
 geos_hasz = UnaryPredicate('GEOSHasZ')
+geos_isclosed = UnaryPredicate('GEOSisClosed')
 geos_isempty = UnaryPredicate('GEOSisEmpty')
 geos_isring = UnaryPredicate('GEOSisRing')
 geos_issimple = UnaryPredicate('GEOSisSimple')
diff --git a/docs/ref/contrib/gis/geos.txt b/docs/ref/contrib/gis/geos.txt
index ddf4f0706f..259221ef23 100644
--- a/docs/ref/contrib/gis/geos.txt
+++ b/docs/ref/contrib/gis/geos.txt
@@ -694,6 +694,12 @@ is returned instead.
 
        In previous versions, an empty ``LineString`` couldn't be instantiated.
 
+   .. attribute:: closed
+
+   .. versionadded:: 1.10
+
+   Returns whether or not this ``LineString`` is closed.
+
 ``LinearRing``
 --------------
 
@@ -790,6 +796,11 @@ Geometry Collections
    Returns a :class:`LineString` representing the line merge of
    all the components in this ``MultiLineString``.
 
+   .. attribute:: closed
+
+   .. versionadded:: 1.10
+
+   Returns ``True`` if and only if all elements are closed. Requires GEOS 3.5.
 
 ``MultiPolygon``
 ----------------
diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt
index 6276f2e102..25998ddc96 100644
--- a/docs/releases/1.10.txt
+++ b/docs/releases/1.10.txt
@@ -104,6 +104,11 @@ Minor features
   of :class:`~django.contrib.gis.geos.WKTWriter` allow controlling
   output of the fractional part of the coordinates in WKT.
 
+* Added the :attr:`LineString.closed
+  <django.contrib.gis.geos.LineString.closed>` and
+  :attr:`MultiLineString.closed
+  <django.contrib.gis.geos.MultiLineString.closed>` properties.
+
 :mod:`django.contrib.messages`
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/gis_tests/geos_tests/test_geos.py b/tests/gis_tests/geos_tests/test_geos.py
index fd08e3037a..116e8d35f8 100644
--- a/tests/gis_tests/geos_tests/test_geos.py
+++ b/tests/gis_tests/geos_tests/test_geos.py
@@ -15,6 +15,7 @@ from django.contrib.gis.geos import (
     fromfile, fromstr,
 )
 from django.contrib.gis.geos.base import GEOSBase
+from django.contrib.gis.geos.libgeos import geos_version_info
 from django.contrib.gis.shortcuts import numpy
 from django.template import Context
 from django.template.engine import Engine
@@ -660,6 +661,20 @@ class GEOSTest(SimpleTestCase, TestDataMixin):
         self.assertTrue(poly.covers(Point(5, 5)))
         self.assertFalse(poly.covers(Point(100, 100)))
 
+    def test_closed(self):
+        ls_closed = LineString((0, 0), (1, 1), (0, 0))
+        ls_not_closed = LineString((0, 0), (1, 1))
+        self.assertFalse(ls_not_closed.closed)
+        self.assertTrue(ls_closed.closed)
+
+        if geos_version_info()['version'] >= '3.5':
+            self.assertFalse(MultiLineString(ls_closed, ls_not_closed).closed)
+            self.assertTrue(MultiLineString(ls_closed, ls_closed).closed)
+
+        with mock.patch('django.contrib.gis.geos.collections.geos_version_info', lambda: {'version': '3.4.9'}):
+            with self.assertRaisesMessage(GEOSException, "MultiLineString.closed requires GEOS >= 3.5.0."):
+                MultiLineString().closed
+
     def test_srid(self):
         "Testing the SRID property and keyword."
         # Testing SRID keyword on Point