TINKERPOP-2963 Changed sparse to untyped for GraphSON

Brought back GraphSON 2 untyped for consistency sake and to setup for the same with GraphSON 3. CTR
diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 3e0f084..3ab6d2d 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -28,7 +28,8 @@
 * Added `text/plain` MIME type to the HTTP endpoint to return a Gremlin Console-like representation of the data.
 * Added GraphBinary serialization option to the HTTP endpoint.
 * Fixed bug with `fail` step not working with a `VertexProgram` running on the server.
-* Introduced new mime-type `application/vnd.gremlin-v1.0+json;sparse=true` to allow direct specification of GraphSON 1.0 without types.
+* Introduced mime type `application/vnd.gremlin-v1.0+json;typed=false` to allow direct specification of GraphSON 1.0 without types.
+* Introduced mime type `application/vnd.gremlin-v2.0+json;typed=false` to allow direct specification of GraphSON 2.0 without types.
 
 [[release-3-6-4]]
 === TinkerPop 3.6.4 (Release Date: May 12, 2023)
diff --git a/docs/src/dev/io/graphson.asciidoc b/docs/src/dev/io/graphson.asciidoc
index f0aa50d..7beb961 100644
--- a/docs/src/dev/io/graphson.asciidoc
+++ b/docs/src/dev/io/graphson.asciidoc
@@ -435,13 +435,27 @@
 
 The following sections discuss the GraphSON object serialization format as available in each version of GraphSON. Core
 to understanding these sections is to understand that GraphSON can be produced with and without types being embedded
-in the output. Without embedded types, the type system is restricted to standard JSON types of Object, List, String,
-Number, Boolean and that will lead to "lossyness" in the format (i.e. a float will be interpreted as double).
+in the output. Without embedded types, the type system is restricted to standard JSON types of `Object`, `List`,
+`String`, `Number`, `Boolean` and that will lead to "lossyness" in the format (i.e. a float will be interpreted as
+double). It is also worth considering that choosing a GraphSON format without embedded types may also restrict the
+type of results that can be obtained. For example, `g.V().groupCount()` returns a format with a `Map`. That's fine
+for GraphSON, but the key in that `Map` is a complex object (i.e. a `Vertex`) and as such is not compatible with JSON
+itself which can only support `String` keys.
+
+WARNING: The `application/json` mime type is shared with all versions of GraphSON and their variations and does not
+reflect a particular one. Servers will return the GraphSON version and variation that this mime type is configured for
+and it could be different (or change) from server to server. When building applications, it is recommended that the
+mime type is made explicit on requests to avoid breaking changes or unexpected results.
 
 [[graphson-1d0]]
 == Version 1.0
 
-Version 1.0 of GraphSON was released with TinkerPop 3.0.0. When types are embedded, GraphSON uses the standard
+Version 1.0 of GraphSON was released with TinkerPop 3.0.0. It is referred to by the following mime types:
+
+* `application/vnd.gremlin-v1.0+json` - types embedded
+* `application/vnd.gremlin-v1.0+json;sparse=true` - no types embedded
+
+When types are embedded, GraphSON uses the standard
 link:https://github.com/FasterXML/jackson-databind[Jackson] type embedding approach that writes the full Java class
 name into a "@class" field in the JSON. While this approach isn't especially language agnostic it does at least give
 some hint as to what the expected type is.
@@ -1138,14 +1152,15 @@
 types. While the <<graphson-1d0,GraphSON 1.0>> section focused on GraphSON without embedded types, GraphSON 2.0 will
 do the opposite as embedded types is the expected manner in which non-JVM languages will interact with TinkerPop.
 
-With GraphSON 2.0, there are essentially two type formats:
+GraphSON 2.0 is referred to by the following mime types:
 
-* A non-typed value which is assumed the type implied by JSON. These non-types are limited to `String`, `Boolean`,
-`Map` and `Collection`.
-* All other values are typed by way of a "complex object" that defines a `@typeId` and `@value`. The `@typeId` is
-composed of two parts: a namespace and a type name, in the format "namespace:typename". A namespace allows TinkerPop
-providers and users to categorize custom types that they may implement and avoid collision with existing TinkerPop
-types. By default, TinkerPop types will have the namespace "g" (or "gx" for "extended" types).
+* `application/vnd.gremlin-v2.0+json` - All other values are typed by way of a "complex object" that defines a
+`@typeId` and `@value`. The `@typeId` is composed of two parts: a namespace and a type name, in the format
+"namespace:typename". A namespace allows TinkerPop providers and users to categorize custom types that they may
+implement and avoid collision with existing TinkerPop types. By default, TinkerPop types will have the namespace "g"
+(or "gx" for "extended" types).
+* `application/vnd.gremlin-v2.0+json;sparse=true` - A non-typed value which is assumed the type implied by JSON.
+These non-types are limited to `String`, `Boolean`, `Map` and `Collection`.
 
 === Core
 
@@ -3836,8 +3851,8 @@
 [[graphson-3d0]]
 == Version 3.0
 
-Version 3.0 of GraphSON was first introduced on TinkerPop 3.3.0 and is the default format when not specified as of this
-version. It is quite similar to GraphSON 2.0 and in most cases will appear compatible to the eye, however there are
+Version 3.0 of GraphSON was first introduced on TinkerPop 3.3.0 and is represented by the `application/vnd.graphbinary-v3.0`
+mime type. It is quite similar to GraphSON 2.0 and in most cases will appear compatible to the eye, however there are
 some critical differences:
 
 * GraphSON 3.0 does not have an option to be typeless. Types are always embedded except for strings and boolean values
diff --git a/docs/src/reference/gremlin-applications.asciidoc b/docs/src/reference/gremlin-applications.asciidoc
index c46b2dc..4a7dee4 100644
--- a/docs/src/reference/gremlin-applications.asciidoc
+++ b/docs/src/reference/gremlin-applications.asciidoc
@@ -1132,12 +1132,37 @@
 available and/or expected keys are dependent on the serializer being used.  Gremlin Server comes packaged with two
 different serializers: GraphSON and GraphBinary.
 
+WARNING: Irrespective of the serialization format chosen, it is highly recommended that the serialization format is
+specified explicitly. For example, prefer `application/vnd.gremlin-v3.0+json` to `application/json`. Use of the drivers
+tend to take care of this issue internally, but for all other mechanisms it is best to ensure the `Accept` type is
+defined this way to avoid possible breaking changes or unexpected results, as defaults may vary from server to server.
+
+WARNING: When connecting with drivers, never try to specify a serialization format that does not have embedded types.
+The drivers are designed to use that type information to properly produce results in the programming language's type
+system and may not function correctly without it. Generally speaking, `GraphBinary` is always the best choice for the
+drivers.
+
 ===== GraphSON
 
 The GraphSON serializer produces human readable output in JSON format and is a good configuration choice for those
 trying to use TinkerPop from non-JVM languages.  JSON obviously has wide support across virtually all major
 programming languages and can be consumed by a wide variety of tools. The format itself is described in the
-link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphson[IO Documentation].
+link:https://tinkerpop.apache.org/docs/x.y.z/dev/io/#graphson[IO Documentation]. The following table shows the
+available GraphSON serializers that can be configured:
+
+[width="100%",cols="2,2,4,4",options="header"]
+|=========================================================
+|Version |Embedded Types |Mime Type |Class
+|1.0 |yes |`application/vnd.gremlin-v1.0+json` |`GraphSONMessageSerializerGremlinV1d0`
+|1.0 |no |`application/vnd.gremlin-v1.0+json;types=false` |`GraphSONUntypedMessageSerializerV1d0`
+|2.0 |yes |`application/vnd.gremlin-v2.0+json` |`GraphSONMessageSerializerV2d0`
+|2.0 |no |`application/vnd.gremlin-v2.0+json;types=false` |`GraphSONUntypedMessageSerializerV2d0`
+|3.0 |yes |`application/vnd.gremlin-v3.0+json` |`GraphSONMessageSerializerV3d0`
+|=========================================================
+
+The above serializer classes can be found in the `org.apache.tinkerpop.gremlin.driver.ser` package of `gremlin-driver`.
+
+Configuring GraphSON in the Gremlin Server configuration looks like this:
 
 [source,yaml]
 ----
diff --git a/docs/src/upgrade/release-3.6.x.asciidoc b/docs/src/upgrade/release-3.6.x.asciidoc
index d54ad7a..db14ee0 100644
--- a/docs/src/upgrade/release-3.6.x.asciidoc
+++ b/docs/src/upgrade/release-3.6.x.asciidoc
@@ -48,6 +48,24 @@
 
 See: link:https://issues.apache.org/jira/browse/TINKERPOP-2947[TINKERPOP-2947]
 
+==== Untyped GraphSON
+
+Prior to GraphSON 3.0, there were options to have GraphSON returned with and without types. The latter was helpful
+for getting a more simple to process JSON format that relied strictly on the JSON type system. This format was of
+course lossy in nature and not conducive for use with the language variants that were developing as the primary
+mechanism for working with Gremlin. Of course, simple HTTP never really went away and forcing the type system on
+consumers makes that route of connecting harder than it should be.
+
+With HTTP users in mind, this version brings back both versions of untyped GraphSON by adding the following mime types:
+
+* GraphSON 1.0 - `application/vnd.gremlin-v1.0+json;types=false`
+* GraphSON 2.0 - `application/vnd.gremlin-v2.0+json;types=false`
+
+Neither is configured by default in Gremlin Server, but can be added if desired by editing the Gremlin Server
+configuration file.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2965[TINKERPOP-2965]
+
 == TinkerPop 3.6.4
 
 *Release Date: May 12, 2023*
diff --git a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java
index 3eb750e..44654d5 100644
--- a/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java
+++ b/gremlin-console/src/main/java/org/apache/tinkerpop/gremlin/console/jsr223/DriverGremlinPlugin.java
@@ -37,9 +37,9 @@
 import org.apache.tinkerpop.gremlin.driver.remote.DriverRemoteTraversal;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0;
-import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV2d0;
-import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphSONUntypedMessageSerializerV1d0;
 import org.apache.tinkerpop.gremlin.driver.ser.MessageTextSerializer;
 import org.apache.tinkerpop.gremlin.driver.ser.SerTokens;
 import org.apache.tinkerpop.gremlin.driver.ser.SerializationException;
@@ -75,9 +75,9 @@
                     ResponseStatus.class,
                     ResponseStatusCode.class,
                     GraphSONMessageSerializerGremlinV1d0.class,
-                    GraphSONMessageSerializerGremlinV2d0.class,
-                    GraphSONMessageSerializerV1d0.class,
+                    GraphSONUntypedMessageSerializerV1d0.class,
                     GraphSONMessageSerializerV2d0.class,
+                    GraphSONMessageSerializerV3d0.class,
                     GraphBinaryMessageSerializerV1.class,
                     MessageTextSerializer.class,
                     SerializationException.class,
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java
index 8b21ec4..615077b 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/MessageSerializer.java
@@ -33,12 +33,13 @@
 import java.util.ServiceLoader;
 
 /**
- * Serializes data to and from Gremlin Server.  Typically the object being serialized or deserialized will be an item
+ * Serializes data to and from Gremlin Server.  Typically, the object being serialized or deserialized will be an item
  * from an {@link Iterator} as returned from the {@code ScriptEngine} or an incoming {@link RequestMessage}.
  * {@link MessageSerializer} instances are instantiated to a cache via {@link ServiceLoader} and indexed based on
- * the mime types they support.  If a mime type is supported more than once, the last {@link MessageSerializer}
- * instance loaded for that mime type is assigned. If a mime type is not found the default
- * {@link GraphSONMessageSerializerV1d0} is used to return the results.
+ * the mime types they support.  If a mime type is supported more than once, the first {@link MessageSerializer}
+ * instance loaded for that mime type is assigned. If a mime type is not found the server default is chosen. The
+ * default may change from version to version so it is best to not rely on it when developing applications and to
+ * always be explicit in specifying the type you wish to bind to.
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0.java
index ef9e0ef..f175c30 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerGremlinV1d0.java
@@ -52,7 +52,7 @@
 
     @Override
     public String[] mimeTypesSupported() {
-        return new String[]{MIME_TYPE};
+        return new String[]{MIME_TYPE, SerTokens.MIME_JSON};
     }
 
     @Override
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
index 67f9d12..87e6b0c 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV1d0.java
@@ -23,7 +23,6 @@
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
@@ -37,10 +36,14 @@
  * Serialize results to JSON with version 1.0.x schema.
  *
  * @author Stephen Mallette (http://stephen.genoprime.com)
+ * @deprecated As of release 3.6.5, replaced by {@link GraphSONUntypedMessageSerializerV1d0}. In the future this will
+ * become what was formerly known as {@link GraphSONMessageSerializerGremlinV1d0} which makes the naming consistent
+ * for all GraphSON versions.
  */
+@Deprecated
 public final class GraphSONMessageSerializerV1d0 extends AbstractGraphSONMessageSerializerV1d0 implements MessageTextSerializer<ObjectMapper> {
     private static final Logger logger = LoggerFactory.getLogger(GraphSONMessageSerializerV1d0.class);
-    private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V1D0_SPARSE;
+    private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V1D0_UNTYPED;
 
     private static byte[] header;
 
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
index 058a393..ae5042d 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0.java
@@ -21,9 +21,7 @@
 import io.netty.buffer.ByteBufAllocator;
 import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
-import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
-import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
 import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
@@ -31,8 +29,6 @@
 import org.slf4j.LoggerFactory;
 
 import java.nio.ByteBuffer;
-import java.util.Map;
-import java.util.UUID;
 
 /**
  * Serialize results to JSON with version 2.0.x schema and the extended module.
@@ -53,10 +49,8 @@
     }
 
     /**
-     * Creates a default GraphSONMessageSerializer.
-     *
-     * By default this will internally instantiate a {@link GraphSONMapper} and register
-     * a {@link GremlinServerModule} and {@link GraphSONXModuleV2d0} to the mapper.
+     * Creates a default GraphSONMessageSerializer. By default this will internally instantiate a {@link GraphSONMapper}
+     * and register a {@link GremlinServerModule} and {@link GraphSONXModuleV2d0} to the mapper.
      *
      * @see #GraphSONMessageSerializerV2d0(GraphSONMapper.Builder)
      */
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV1d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV1d0.java
new file mode 100644
index 0000000..a9979f0
--- /dev/null
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV1d0.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Serialize results to JSON with version 1.0.x schema and sparse serialization which does not embed types.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class GraphSONUntypedMessageSerializerV1d0 extends AbstractGraphSONMessageSerializerV1d0 implements MessageTextSerializer<ObjectMapper> {
+    private static final Logger logger = LoggerFactory.getLogger(GraphSONUntypedMessageSerializerV1d0.class);
+    private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V1D0_UNTYPED;
+
+    private static byte[] header;
+
+    static {
+        final ByteBuffer buffer = ByteBuffer.allocate(MIME_TYPE.length() + 1);
+        buffer.put((byte) MIME_TYPE.length());
+        buffer.put(MIME_TYPE.getBytes());
+        header = buffer.array();
+    }
+
+    public GraphSONUntypedMessageSerializerV1d0() {
+        super();
+    }
+
+    public GraphSONUntypedMessageSerializerV1d0(final GraphSONMapper mapper) {
+        super(mapper);
+    }
+
+    @Override
+    public String[] mimeTypesSupported() {
+        return new String[]{MIME_TYPE, SerTokens.MIME_JSON};
+    }
+
+    @Override
+    GraphSONMapper.Builder configureBuilder(final GraphSONMapper.Builder builder) {
+        // already set to 1.0 in AbstractGraphSONMessageSerializerV1d0
+        return builder.addCustomModule(new GremlinServerModule())
+                .typeInfo(TypeInfo.NO_TYPES);
+    }
+
+    @Override
+    byte[] obtainHeader() {
+        return header;
+    }
+
+    @Override
+    public ResponseMessage deserializeResponse(final String msg) throws SerializationException {
+        try {
+            final Map<String, Object> responseData = mapper.readValue(msg, mapTypeReference);
+            final Map<String, Object> status = (Map<String, Object>) responseData.get(SerTokens.TOKEN_STATUS);
+            final Map<String, Object> result = (Map<String, Object>) responseData.get(SerTokens.TOKEN_RESULT);
+            return ResponseMessage.build(UUID.fromString(responseData.get(SerTokens.TOKEN_REQUEST).toString()))
+                    .code(ResponseStatusCode.getFromValue((Integer) status.get(SerTokens.TOKEN_CODE)))
+                    .statusMessage(String.valueOf(status.get(SerTokens.TOKEN_MESSAGE)))
+                    .statusAttributes((Map<String, Object>) status.get(SerTokens.TOKEN_ATTRIBUTES))
+                    .result(result.get(SerTokens.TOKEN_DATA))
+                    .responseMetaData((Map<String, Object>) result.get(SerTokens.TOKEN_META))
+                    .create();
+        } catch (Exception ex) {
+            logger.warn("Response [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV1d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+
+    @Override
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
+        try {
+            return mapper.writeValueAsString(responseMessage);
+        } catch (Exception ex) {
+            logger.warn("Response [{}] could not be serialized by {}.", responseMessage.toString(), AbstractGraphSONMessageSerializerV1d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+
+    @Override
+    public RequestMessage deserializeRequest(final String msg) throws SerializationException {
+        try {
+            return mapper.readValue(msg, RequestMessage.class);
+        } catch (Exception ex) {
+            logger.warn("Request [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV1d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+
+    @Override
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
+        try {
+            return mapper.writeValueAsString(requestMessage);
+        } catch (Exception ex) {
+            logger.warn("Request [{}] could not be serialized by {}.", requestMessage.toString(), AbstractGraphSONMessageSerializerV1d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+}
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV2d0.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV2d0.java
new file mode 100644
index 0000000..5d77d4a
--- /dev/null
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV2d0.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONMapper;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.TypeInfo;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Serialize results to JSON with version 2.0.x schema and the extended module without embedded types.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public final class GraphSONUntypedMessageSerializerV2d0 extends AbstractGraphSONMessageSerializerV2d0 implements MessageTextSerializer<ObjectMapper> {
+    private static final Logger logger = LoggerFactory.getLogger(GraphSONUntypedMessageSerializerV2d0.class);
+    private static final String MIME_TYPE = SerTokens.MIME_GRAPHSON_V2D0_UNTYPED;
+
+    private static byte[] header;
+
+    static {
+        final ByteBuffer buffer = ByteBuffer.allocate(MIME_TYPE.length() + 1);
+        buffer.put((byte) MIME_TYPE.length());
+        buffer.put(MIME_TYPE.getBytes());
+        header = buffer.array();
+    }
+
+    /**
+     * Creates a default GraphSONMessageSerializer.
+     *
+     * By default this will internally instantiate a {@link GraphSONMapper} and register
+     * a {@link GremlinServerModule} and {@link GraphSONXModuleV2d0} to the mapper.
+     *
+     * @see #GraphSONUntypedMessageSerializerV2d0(GraphSONMapper.Builder)
+     */
+    public GraphSONUntypedMessageSerializerV2d0() {
+        super();
+    }
+
+    /**
+     * Create a GraphSONMessageSerializer from a {@link GraphSONMapper}. Deprecated, use
+     * {@link #GraphSONUntypedMessageSerializerV2d0(GraphSONMapper.Builder)} instead.
+     */
+    @Deprecated
+    public GraphSONUntypedMessageSerializerV2d0(final GraphSONMapper mapper) {
+        super(mapper);
+    }
+
+    /**
+     * Create a GraphSONMessageSerializer with a provided {@link GraphSONMapper.Builder}.
+     *
+     * Note that to make this mapper usable in the context of request messages and responses,
+     * this method will automatically register a {@link GremlinServerModule} to the provided
+     * mapper.
+     */
+    public GraphSONUntypedMessageSerializerV2d0(final GraphSONMapper.Builder mapperBuilder) {
+        super(mapperBuilder);
+    }
+
+    @Override
+    public String[] mimeTypesSupported() {
+        return new String[]{MIME_TYPE, SerTokens.MIME_JSON};
+    }
+
+    @Override
+    GraphSONMapper.Builder configureBuilder(final GraphSONMapper.Builder builder) {
+        // already set to 2.0 in AbstractGraphSONMessageSerializerV2d0
+        return builder.typeInfo(TypeInfo.NO_TYPES).addCustomModule(new GremlinServerModule());
+    }
+
+    @Override
+    byte[] obtainHeader() {
+        return header;
+    }
+
+    @Override
+    public ResponseMessage deserializeResponse(final String msg) throws SerializationException {
+        try {
+            return mapper.readValue(msg, ResponseMessage.class);
+        } catch (Exception ex) {
+            logger.warn("Response [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+
+    @Override
+    public String serializeResponseAsString(final ResponseMessage responseMessage, final ByteBufAllocator allocator) throws SerializationException {
+        try {
+            return mapper.writeValueAsString(responseMessage);
+        } catch (Exception ex) {
+            logger.warn("Response [{}] could not be serialized by {}.", responseMessage.toString(), AbstractGraphSONMessageSerializerV2d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+
+    @Override
+    public RequestMessage deserializeRequest(final String msg) throws SerializationException {
+        try {
+            return mapper.readValue(msg, RequestMessage.class);
+        } catch (Exception ex) {
+            logger.warn("Request [{}] could not be deserialized by {}.", msg, AbstractGraphSONMessageSerializerV2d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+
+    @Override
+    public String serializeRequestAsString(final RequestMessage requestMessage, final ByteBufAllocator allocator) throws SerializationException {
+        try {
+            return mapper.writeValueAsString(requestMessage);
+        } catch (Exception ex) {
+            logger.warn("Request [{}] could not be serialized by {}.", requestMessage.toString(), AbstractGraphSONMessageSerializerV2d0.class.getName());
+            throw new SerializationException(ex);
+        }
+    }
+}
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/SerTokens.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/SerTokens.java
index a1b92d3..0a437e3 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/SerTokens.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/SerTokens.java
@@ -18,8 +18,6 @@
  */
 package org.apache.tinkerpop.gremlin.driver.ser;
 
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy;
-
 /**
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
@@ -40,8 +38,9 @@
 
     public static final String MIME_JSON = "application/json";
     public static final String MIME_GRAPHSON_V1D0 = "application/vnd.gremlin-v1.0+json";
-    public static final String MIME_GRAPHSON_V1D0_SPARSE = "application/vnd.gremlin-v1.0+json;sparse=true";
+    public static final String MIME_GRAPHSON_V1D0_UNTYPED = "application/vnd.gremlin-v1.0+json;types=false";
     public static final String MIME_GRAPHSON_V2D0 = "application/vnd.gremlin-v2.0+json";
+    public static final String MIME_GRAPHSON_V2D0_UNTYPED = "application/vnd.gremlin-v2.0+json;types=false";
     public static final String MIME_GRAPHSON_V3D0 = "application/vnd.gremlin-v3.0+json";
     public static final String MIME_GRAPHBINARY_V1D0 = "application/vnd.graphbinary-v1.0";
 }
diff --git a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java
index 2a635bf..7c06ff6 100644
--- a/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java
+++ b/gremlin-driver/src/main/java/org/apache/tinkerpop/gremlin/driver/ser/Serializers.java
@@ -19,7 +19,6 @@
 package org.apache.tinkerpop.gremlin.driver.ser;
 
 import org.apache.tinkerpop.gremlin.driver.MessageSerializer;
-import org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.HaltedTraverserStrategy;
 
 /**
  * An enum of the default serializers.
@@ -32,9 +31,30 @@
      * GraphSON 3.0.
      */
     GRAPHSON(SerTokens.MIME_JSON),
+
+    /**
+     * GraphSON 1.0 with types.
+     */
     GRAPHSON_V1D0(SerTokens.MIME_GRAPHSON_V1D0),
-    GRAPHSON_V1D0_SPARSE(SerTokens.MIME_GRAPHSON_V1D0_SPARSE),
+
+    /**
+     * GraphSON 2.0 without types.
+     */
+    GRAPHSON_V1D0_UNTYPED(SerTokens.MIME_GRAPHSON_V1D0_UNTYPED),
+
+    /**
+     * GraphSON 2.0 with types.
+     */
     GRAPHSON_V2D0(SerTokens.MIME_GRAPHSON_V2D0),
+
+    /**
+     * GraphSON 2.0 without types.
+     */
+    GRAPHSON_V2D0_UNTYPED(SerTokens.MIME_GRAPHSON_V2D0_UNTYPED),
+
+    /**
+     * GraphSON 3.0 with types.
+     */
     GRAPHSON_V3D0(SerTokens.MIME_GRAPHSON_V3D0),
     GRAPHBINARY_V1D0(SerTokens.MIME_GRAPHBINARY_V1D0);
 
@@ -55,10 +75,12 @@
                 return new GraphSONMessageSerializerV3d0();
             case SerTokens.MIME_GRAPHSON_V1D0:
                 return new GraphSONMessageSerializerGremlinV1d0();
-            case SerTokens.MIME_GRAPHSON_V1D0_SPARSE:
-                return new GraphSONMessageSerializerV1d0();
+            case SerTokens.MIME_GRAPHSON_V1D0_UNTYPED:
+                return new GraphSONUntypedMessageSerializerV1d0();
             case SerTokens.MIME_GRAPHSON_V2D0:
                 return new GraphSONMessageSerializerV2d0();
+            case SerTokens.MIME_GRAPHSON_V2D0_UNTYPED:
+                return new GraphSONUntypedMessageSerializerV2d0();
             case SerTokens.MIME_GRAPHBINARY_V1D0:
                 return new GraphBinaryMessageSerializerV1();
             default:
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
index 3d01af4..9a2d073 100644
--- a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONMessageSerializerV2d0Test.java
@@ -40,6 +40,7 @@
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONVersion;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONWriter;
 import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONXModuleV2d0;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.TinkerPopJacksonModule;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
@@ -51,6 +52,7 @@
 import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
 import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
 import org.apache.tinkerpop.shaded.jackson.databind.node.NullNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdScalarSerializer;
 import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
 import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat;
 import org.junit.Test;
@@ -95,7 +97,7 @@
 
     @Test
     public void shouldConfigureIoRegistry() throws Exception {
-        final GraphSONMessageSerializerV1d0 serializer = new GraphSONMessageSerializerV1d0();
+        final GraphSONMessageSerializerV2d0 serializer = new GraphSONMessageSerializerV2d0();
         final Map<String, Object> config = new HashMap<String, Object>() {{
             put(AbstractMessageSerializer.TOKEN_IO_REGISTRIES, Arrays.asList(ColorIoRegistry.class.getName()));
         }};
@@ -107,7 +109,8 @@
         final String results = serializer.serializeResponseAsString(toSerialize, allocator);
         final JsonNode json = mapper.readTree(results);
         assertNotNull(json);
-        assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).booleanValue(), is(true));
+        assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).get(GraphSONTokens.VALUEPROP).booleanValue(), is(true));
+        assertEquals("java:color", json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).get(GraphSONTokens.VALUETYPE).textValue());
     }
 
     @Test
@@ -594,15 +597,26 @@
         }
     }
 
-    public static class ColorSimpleModule extends SimpleModule {
+    public static class ColorSimpleModule extends TinkerPopJacksonModule {
         public ColorSimpleModule() {
             super("color-fun");
             addSerializer(Color.class, new ColorSerializer());
+        }
 
+        @Override
+        public Map<Class, String> getTypeDefinitions() {
+            return new HashMap<Class, String>(){{
+                put(Color.class, "color");
+            }};
+        }
+
+        @Override
+        public String getTypeNamespace() {
+            return "java";
         }
     }
 
-    public static class ColorSerializer extends StdSerializer<Color> {
+    public static class ColorSerializer extends StdScalarSerializer<Color> {
         public ColorSerializer() {
             super(Color.class);
         }
diff --git a/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV1d0Test.java b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV1d0Test.java
new file mode 100644
index 0000000..0affec6
--- /dev/null
+++ b/gremlin-driver/src/test/java/org/apache/tinkerpop/gremlin/driver/ser/GraphSONUntypedMessageSerializerV1d0Test.java
@@ -0,0 +1,512 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.tinkerpop.gremlin.driver.ser;
+
+import io.netty.buffer.ByteBufAllocator;
+import org.apache.tinkerpop.gremlin.driver.message.RequestMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
+import org.apache.tinkerpop.gremlin.driver.message.ResponseStatusCode;
+import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
+import org.apache.tinkerpop.gremlin.process.traversal.step.util.Tree;
+import org.apache.tinkerpop.gremlin.structure.Edge;
+import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.Property;
+import org.apache.tinkerpop.gremlin.structure.Vertex;
+import org.apache.tinkerpop.gremlin.structure.VertexProperty;
+import org.apache.tinkerpop.gremlin.structure.io.AbstractIoRegistry;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONIo;
+import org.apache.tinkerpop.gremlin.structure.io.graphson.GraphSONTokens;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory;
+import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
+import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerationException;
+import org.apache.tinkerpop.shaded.jackson.core.JsonGenerator;
+import org.apache.tinkerpop.shaded.jackson.databind.JsonNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ObjectMapper;
+import org.apache.tinkerpop.shaded.jackson.databind.SerializerProvider;
+import org.apache.tinkerpop.shaded.jackson.databind.module.SimpleModule;
+import org.apache.tinkerpop.shaded.jackson.databind.node.NullNode;
+import org.apache.tinkerpop.shaded.jackson.databind.ser.std.StdSerializer;
+import org.apache.tinkerpop.shaded.jackson.databind.util.StdDateFormat;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.awt.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+/**
+ * These tests focus on message serialization and not "result" serialization as test specific to results (e.g.
+ * vertices, edges, annotated values, etc.) are handled in the IO packages.
+ *
+ * @author Stephen Mallette (http://stephen.genoprime.com)
+ */
+public class GraphSONUntypedMessageSerializerV1d0Test {
+
+    public static final GraphSONUntypedMessageSerializerV1d0 SERIALIZER = new GraphSONUntypedMessageSerializerV1d0();
+    private static final RequestMessage msg = RequestMessage.build("op")
+            .overrideRequestId(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595")).create();
+    private static final ObjectMapper mapper = new ObjectMapper();
+    private static final ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
+
+    @Test
+    public void shouldConfigureIoRegistry() throws Exception {
+        final GraphSONUntypedMessageSerializerV1d0 serializer = new GraphSONUntypedMessageSerializerV1d0();
+        final Map<String, Object> config = new HashMap<String, Object>() {{
+            put(AbstractMessageSerializer.TOKEN_IO_REGISTRIES, Arrays.asList(ColorIoRegistry.class.getName()));
+        }};
+
+        serializer.configure(config, null);
+
+        final ResponseMessage toSerialize = ResponseMessage.build(UUID.fromString("2D62161B-9544-4F39-AF44-62EC49F9A595"))
+                .result(Color.RED).create();
+        final String results = serializer.serializeResponseAsString(toSerialize, allocator);
+        final JsonNode json = mapper.readTree(results);
+        assertNotNull(json);
+        assertThat(json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA).booleanValue(), is(true));
+    }
+
+    @Test
+    public void shouldSerializeToJsonNullResultReturnsNull() throws Exception {
+        final ResponseMessage message = ResponseMessage.build(msg).create();
+        final String results = SERIALIZER.serializeResponseAsString(message, allocator);
+        final JsonNode json = mapper.readTree(results);
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.path(SerTokens.TOKEN_REQUEST).asText());
+        assertEquals(NullNode.getInstance(), json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA));
+    }
+
+    @Test
+    public void shouldSerializeToJsonIterable() throws Exception {
+        final ArrayList<FunObject> funList = new ArrayList<>();
+        funList.add(new FunObject("x"));
+        funList.add(new FunObject("y"));
+
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList).create(), allocator);
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertEquals(2, converted.size());
+
+        assertEquals("x", converted.get(0).asText());
+        assertEquals("y", converted.get(1).asText());
+    }
+
+    @Test
+    public void shouldSerializeToJsonIterator() throws Exception {
+        final ArrayList<FunObject> funList = new ArrayList<>();
+        funList.add(new FunObject("x"));
+        funList.add(new FunObject("y"));
+
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create(), allocator);
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertEquals(2, converted.size());
+
+        assertEquals("x", converted.get(0).asText());
+        assertEquals("y", converted.get(1).asText());
+    }
+
+    @Test
+    public void shouldSerializeToJsonIteratorNullElement() throws Exception {
+
+        final ArrayList<FunObject> funList = new ArrayList<>();
+        funList.add(new FunObject("x"));
+        funList.add(null);
+        funList.add(new FunObject("y"));
+
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(funList.iterator()).create(), allocator);
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertEquals(3, converted.size());
+
+        assertEquals("x", converted.get(0).asText());
+        assertEquals(NullNode.getInstance(), converted.get(1));
+        assertEquals("y", converted.get(2).asText());
+    }
+
+    @Test
+    public void shouldSerializeToJsonMap() throws Exception {
+        final Map<String, Object> map = new HashMap<>();
+        final Map<String, String> innerMap = new HashMap<>();
+        innerMap.put("a", "b");
+
+        map.put("x", new FunObject("x"));
+        map.put("y", "some");
+        map.put("z", innerMap);
+
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode jsonObject = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertNotNull(jsonObject);
+        assertEquals("some", jsonObject.get("y").asText());
+        assertEquals("x", jsonObject.get("x").asText());
+
+        final JsonNode innerJsonObject = jsonObject.get("z");
+        assertNotNull(innerJsonObject);
+        assertEquals("b", innerJsonObject.get("a").asText());
+    }
+
+    @Test
+    public void shouldShouldSerializeMapEntries() throws Exception {
+        final Graph graph = TinkerGraph.open();
+        final Vertex v1 = graph.addVertex();
+        final Date d = new Date();
+
+        final Map<Object, Object> map = new HashMap<>();
+        map.put("x", 1);
+        map.put(v1, 100);
+        map.put(d, "test");
+
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(IteratorUtils.asList(map)).create(), allocator);
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode jsonObject = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+        jsonObject.elements().forEachRemaining(e -> {
+            if (e.has("x"))
+                assertEquals(1, e.get("x").asInt());
+            else if (e.has(v1.id().toString()))
+                assertEquals(100, e.get(v1.id().toString()).asInt());
+            else if (e.has(StdDateFormat.instance.format(d)))
+                assertEquals("test", e.get(StdDateFormat.instance.format(d)).asText());
+            else
+                fail("Map entries contains a key that is not part of what was serialized");
+        });
+    }
+
+    @Test
+    public void shouldSerializeEdge() throws Exception {
+        final Graph g = TinkerGraph.open();
+        final Vertex v1 = g.addVertex();
+        final Vertex v2 = g.addVertex();
+        final Edge e = v1.addEdge("test", v2);
+        e.property("abc", 123);
+
+        final Iterable<Edge> iterable = IteratorUtils.list(g.edges());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
+
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertNotNull(converted);
+        assertEquals(1, converted.size());
+
+        final JsonNode edgeAsJson = converted.get(0);
+        assertNotNull(edgeAsJson);
+
+        assertEquals(((Long) e.id()).intValue(), edgeAsJson.get(GraphSONTokens.ID).asLong());  // lossy
+        assertEquals(((Long) v1.id()).intValue(), edgeAsJson.get(GraphSONTokens.OUT).asLong());// lossy
+        assertEquals(((Long) v2.id()).intValue(), edgeAsJson.get(GraphSONTokens.IN).asLong()); // lossy
+        assertEquals(e.label(), edgeAsJson.get(GraphSONTokens.LABEL).asText());
+        assertEquals(GraphSONTokens.EDGE, edgeAsJson.get(GraphSONTokens.TYPE).asText());
+
+        final JsonNode properties = edgeAsJson.get(GraphSONTokens.PROPERTIES);
+        assertNotNull(properties);
+        assertEquals(123, properties.get("abc").asInt());
+    }
+
+    @Test
+    public void shouldSerializeEdgeProperty() throws Exception {
+        final Graph g = TinkerGraph.open();
+        final Vertex v1 = g.addVertex();
+        final Vertex v2 = g.addVertex();
+        final Edge e = v1.addEdge("test", v2);
+        e.property("abc", 123);
+
+        final Iterable<Property<Object>> iterable = IteratorUtils.list(e.properties("abc"));
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
+
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertNotNull(converted);
+        assertEquals(1, converted.size());
+
+        final JsonNode propertyAsJson = converted.get(0);
+        assertNotNull(propertyAsJson);
+
+        assertEquals(123, propertyAsJson.get("value").asInt());
+    }
+
+    @Test
+    public void shouldSerializeToJsonIteratorWithEmbeddedMap() throws Exception {
+        final Graph g = TinkerGraph.open();
+        final Vertex v = g.addVertex();
+        final Map<String, Object> map = new HashMap<>();
+        map.put("x", 500);
+        map.put("y", "some");
+
+        final ArrayList<Object> friends = new ArrayList<>();
+        friends.add("x");
+        friends.add(5);
+        friends.add(map);
+
+        v.property(VertexProperty.Cardinality.single, "friends", friends);
+
+        final Iterable iterable = IteratorUtils.list(g.vertices());
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(iterable).create(), allocator);
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertNotNull(converted);
+        assertEquals(1, converted.size());
+
+        final JsonNode vertexAsJson = converted.get(0);
+        assertNotNull(vertexAsJson);
+
+        final JsonNode properties = vertexAsJson.get(GraphSONTokens.PROPERTIES);
+        assertNotNull(properties);
+        assertEquals(1, properties.size());
+
+        final JsonNode friendProperties = properties.get("friends");
+        assertEquals(1, friendProperties.size());
+        final JsonNode friendsProperty = friendProperties.get(0);
+        assertNotNull(friendsProperty);
+        assertEquals(3, friends.size());
+
+        final String object1 = friendsProperty.get(GraphSONTokens.VALUE).get(0).asText();
+        assertEquals("x", object1);
+
+        final int object2 = friendsProperty.get(GraphSONTokens.VALUE).get(1).asInt();
+        assertEquals(5, object2);
+
+        final JsonNode object3 = friendsProperty.get(GraphSONTokens.VALUE).get(2);
+        assertEquals(500, object3.get("x").asInt());
+        assertEquals("some", object3.get("y").asText());
+    }
+
+    @Test
+    public void shouldSerializeToJsonMapWithElementForKey() throws Exception {
+        final TinkerGraph graph = TinkerFactory.createClassic();
+        final GraphTraversalSource g = graph.traversal();
+        final Map<Vertex, Integer> map = new HashMap<>();
+        map.put(g.V().has("name", "marko").next(), 1000);
+
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(map).create(), allocator);
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+
+        assertNotNull(converted);
+
+        // with no embedded types the key (which is a vertex) simply serializes out to an id
+        // {"result":{"1":1000},"code":200,"requestId":"2d62161b-9544-4f39-af44-62ec49f9a595","type":0}
+        assertEquals(1000, converted.get("1").asInt());
+    }
+
+    @Test
+    public void shouldDeserializeRequestNicelyWithNoArgs() throws Exception {
+        final UUID request = UUID.fromString("011CFEE9-F640-4844-AC93-034448AC0E80");
+        final RequestMessage m = SERIALIZER.deserializeRequest(String.format("{\"requestId\":\"%s\",\"op\":\"eval\"}", request));
+        assertEquals(request, m.getRequestId());
+        assertEquals("eval", m.getOp());
+        assertNotNull(m.getArgs());
+        assertEquals(0, m.getArgs().size());
+    }
+
+    @Test
+    public void shouldDeserializeRequestNicelyWithArgs() throws Exception {
+        final UUID request = UUID.fromString("011CFEE9-F640-4844-AC93-034448AC0E80");
+        final RequestMessage m = SERIALIZER.deserializeRequest(String.format("{\"requestId\":\"%s\",\"op\":\"eval\",\"args\":{\"x\":\"y\"}}", request));
+        assertEquals(request, m.getRequestId());
+        assertEquals("eval", m.getOp());
+        assertNotNull(m.getArgs());
+        assertEquals("y", m.getArgs().get("x"));
+    }
+
+    @Test(expected = SerializationException.class)
+    public void shouldDeserializeRequestParseMessage() throws Exception {
+        SERIALIZER.deserializeRequest("{\"requestId\":\"%s\",\"op\":\"eval\",\"args\":{\"x\":\"y\"}}");
+    }
+
+    @Test
+    public void shouldSerializeFullResponseMessage() throws Exception {
+        final UUID id = UUID.randomUUID();
+
+        final Map<String, Object> metaData = new HashMap<>();
+        metaData.put("test", "this");
+        metaData.put("one", 1);
+
+        final Map<String, Object> attributes = new HashMap<>();
+        attributes.put("test", "that");
+        attributes.put("two", 2);
+
+        final ResponseMessage response = ResponseMessage.build(id)
+                .responseMetaData(metaData)
+                .code(ResponseStatusCode.SUCCESS)
+                .result("some-result")
+                .statusAttributes(attributes)
+                .statusMessage("worked")
+                .create();
+
+        final String results = SERIALIZER.serializeResponseAsString(response, allocator);
+        final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
+
+        assertEquals(id, deserialized.getRequestId());
+        assertEquals("this", deserialized.getResult().getMeta().get("test"));
+        assertEquals(1, deserialized.getResult().getMeta().get("one"));
+        assertEquals("some-result", deserialized.getResult().getData());
+        assertEquals("that", deserialized.getStatus().getAttributes().get("test"));
+        assertEquals(2, deserialized.getStatus().getAttributes().get("two"));
+        assertEquals(ResponseStatusCode.SUCCESS.getValue(), deserialized.getStatus().getCode().getValue());
+        assertEquals("worked", deserialized.getStatus().getMessage());
+    }
+
+    @Test
+    public void shouldDeserializeResponseMessageWithNullMessage() throws Exception {
+        final UUID id = UUID.randomUUID();
+
+        final Map<String, Object> metaData = new HashMap<>();
+        metaData.put("test", UUID.randomUUID().toString());
+        final Map<String, Object> attributes = Collections.emptyMap();
+
+        final ResponseMessage response = ResponseMessage.build(id)
+                .responseMetaData(metaData)
+                .code(ResponseStatusCode.SERVER_ERROR)
+                .result("some-result")
+                .statusAttributes(attributes)
+                // explicitly pass the null value
+                .statusMessage(null)
+                .create();
+
+        final String results = SERIALIZER.serializeResponseAsString(response, allocator);
+        final ResponseMessage deserialized = SERIALIZER.deserializeResponse(results);
+        Assert.assertNotNull(SERIALIZER.getClass().getSimpleName() + " should be able to deserialize ResponseMessage "
+                        + "with null message field", deserialized);
+    }
+
+    @Test
+    public void shouldSerializeToJsonTree() throws Exception {
+        final TinkerGraph graph = TinkerFactory.createClassic();
+        final GraphTraversalSource g = graph.traversal();
+        final Tree t = g.V(1).out().properties("name").tree().next();
+
+        
+        final String results = SERIALIZER.serializeResponseAsString(ResponseMessage.build(msg).result(t).create(), allocator);
+
+        final JsonNode json = mapper.readTree(results);
+
+        assertNotNull(json);
+        assertEquals(msg.getRequestId().toString(), json.get(SerTokens.TOKEN_REQUEST).asText());
+        final JsonNode converted = json.get(SerTokens.TOKEN_RESULT).get(SerTokens.TOKEN_DATA);
+        assertNotNull(converted);
+        
+        //check the first object and it's properties
+        assertEquals(1, converted.get("1").get("key").get("id").asInt());
+        assertEquals("marko", converted.get("1").get("key").get("properties").get("name").get(0).get("value").asText());
+        
+        //check objects tree structure
+        //check Vertex property
+        assertEquals("vadas", converted.get("1")
+                                 .get("value")
+                                 .get("2")
+                                 .get("value")
+                                 .get("3").get("key").get("value").asText());
+        assertEquals("name", converted.get("1")
+                                 .get("value")
+                                 .get("2")
+                                 .get("value")
+                                 .get("3").get("key").get("label").asText());
+        
+        // check subitem
+        assertEquals("lop", converted.get("1")
+                                 .get("value")
+                                 .get("3")
+                                 .get("key")
+                                 .get("properties").get("name").get(0).get("value").asText());
+    }
+
+    private class FunObject {
+        private String val;
+
+        public FunObject(String val) {
+            this.val = val;
+        }
+
+        public String toString() {
+            return this.val;
+        }
+    }
+
+    public static class ColorIoRegistry extends AbstractIoRegistry {
+        public ColorIoRegistry() {
+            register(GraphSONIo.class, null, new ColorSimpleModule());
+        }
+    }
+
+    public static class ColorSimpleModule extends SimpleModule {
+        public ColorSimpleModule() {
+            super("color-fun");
+            addSerializer(Color.class, new ColorSerializer());
+
+        }
+    }
+
+    public static class ColorSerializer extends StdSerializer<Color> {
+        public ColorSerializer() {
+            super(Color.class);
+        }
+
+        @Override
+        public void serialize(final Color color, final JsonGenerator jsonGenerator,
+                              final SerializerProvider serializerProvider) throws IOException, JsonGenerationException {
+            jsonGenerator.writeBoolean(color.equals(Color.RED));
+        }
+    }
+}
diff --git a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
index 664cb58..5306490 100644
--- a/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
+++ b/gremlin-server/src/test/java/org/apache/tinkerpop/gremlin/server/GremlinServerHttpIntegrateTest.java
@@ -22,10 +22,12 @@
 import org.apache.http.HttpHeaders;
 import org.apache.tinkerpop.gremlin.driver.message.ResponseMessage;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphBinaryMessageSerializerV1;
-import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV1d0;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerGremlinV1d0;
 import org.apache.tinkerpop.gremlin.driver.Tokens;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV2d0;
 import org.apache.tinkerpop.gremlin.driver.ser.GraphSONMessageSerializerV3d0;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphSONUntypedMessageSerializerV1d0;
+import org.apache.tinkerpop.gremlin.driver.ser.GraphSONUntypedMessageSerializerV2d0;
 import org.apache.tinkerpop.gremlin.driver.ser.SerTokens;
 import org.apache.tinkerpop.gremlin.server.auth.SimpleAuthenticator;
 import org.apache.tinkerpop.gremlin.server.channel.HttpChannelizer;
@@ -95,7 +97,7 @@
             case "should200OnPOSTWithGraphSON1d0AcceptHeaderDefaultResultToJson":
                 settings.serializers.clear();
                 final Settings.SerializerSettings serializerSettingsV1 = new Settings.SerializerSettings();
-                serializerSettingsV1.className = GraphSONMessageSerializerV1d0.class.getName();
+                serializerSettingsV1.className = GraphSONUntypedMessageSerializerV1d0.class.getName();
                 settings.serializers.add(serializerSettingsV1);
                 break;
             case "should200OnPOSTWithGraphSON2d0AcceptHeaderDefaultResultToJson":
@@ -112,15 +114,21 @@
                 break;
             case "should200OnPOSTWithAnyGraphSONAcceptHeaderDefaultResultToJson":
                 settings.serializers.clear();
-                final Settings.SerializerSettings serializerSettingsAllV1 = new Settings.SerializerSettings();
-                serializerSettingsAllV1.className = GraphSONMessageSerializerV1d0.class.getName();
-                settings.serializers.add(serializerSettingsAllV1);
-                final Settings.SerializerSettings serializerSettingsAllV2 = new Settings.SerializerSettings();
-                serializerSettingsAllV2.className = GraphSONMessageSerializerV2d0.class.getName();
-                settings.serializers.add(serializerSettingsAllV2);
-                final Settings.SerializerSettings serializerSettingsAllV3 = new Settings.SerializerSettings();
-                serializerSettingsAllV3.className = GraphSONMessageSerializerV3d0.class.getName();
-                settings.serializers.add(serializerSettingsAllV3);
+                final Settings.SerializerSettings serializerSettingsSparseV1 = new Settings.SerializerSettings();
+                serializerSettingsSparseV1.className = GraphSONUntypedMessageSerializerV1d0.class.getName();
+                settings.serializers.add(serializerSettingsSparseV1);
+                final Settings.SerializerSettings serializerSettingsTypedV1 = new Settings.SerializerSettings();
+                serializerSettingsTypedV1.className = GraphSONMessageSerializerGremlinV1d0.class.getName();
+                settings.serializers.add(serializerSettingsTypedV1);
+                final Settings.SerializerSettings serializerSettingsSparseV2 = new Settings.SerializerSettings();
+                serializerSettingsSparseV2.className = GraphSONUntypedMessageSerializerV2d0.class.getName();
+                settings.serializers.add(serializerSettingsSparseV2);
+                final Settings.SerializerSettings serializerSettingsTypedV2 = new Settings.SerializerSettings();
+                serializerSettingsTypedV2.className = GraphSONMessageSerializerV2d0.class.getName();
+                settings.serializers.add(serializerSettingsTypedV2);
+                final Settings.SerializerSettings serializerSettingsTypedV3 = new Settings.SerializerSettings();
+                serializerSettingsTypedV3.className = GraphSONMessageSerializerV3d0.class.getName();
+                settings.serializers.add(serializerSettingsTypedV3);
                 break;
             case "should401OnGETWithNoAuthorizationHeader":
             case "should401OnPOSTWithNoAuthorizationHeader":
@@ -931,12 +939,12 @@
 
         final HttpPost httppost1Sparse = new HttpPost(TestClientFactory.createURLString());
         httppost1Sparse.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON);
-        httppost1Sparse.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V1D0_SPARSE);
+        httppost1Sparse.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V1D0_UNTYPED);
         httppost1Sparse.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8));
 
         try (final CloseableHttpResponse response = httpclient.execute(httppost1Sparse)) {
             assertEquals(200, response.getStatusLine().getStatusCode());
-            assertEquals(SerTokens.MIME_GRAPHSON_V1D0_SPARSE, response.getEntity().getContentType().getValue());
+            assertEquals(SerTokens.MIME_GRAPHSON_V1D0_UNTYPED, response.getEntity().getContentType().getValue());
             final String json = EntityUtils.toString(response.getEntity());
             final JsonNode node = mapper.readTree(json);
             assertEquals(0, node.get("result").get("data").get(0).asInt());
@@ -955,6 +963,19 @@
             assertEquals(0, node.get("result").get("data").get(0).get(GraphSONTokens.VALUEPROP).asInt());
         }
 
+        final HttpPost httppost2Sparse = new HttpPost(TestClientFactory.createURLString());
+        httppost2Sparse.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON);
+        httppost2Sparse.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V2D0_UNTYPED);
+        httppost2Sparse.setEntity(new StringEntity("{\"gremlin\":\"1-1\"}", Consts.UTF_8));
+
+        try (final CloseableHttpResponse response = httpclient.execute(httppost2Sparse)) {
+            assertEquals(200, response.getStatusLine().getStatusCode());
+            assertEquals(SerTokens.MIME_GRAPHSON_V2D0_UNTYPED, response.getEntity().getContentType().getValue());
+            final String json = EntityUtils.toString(response.getEntity());
+            final JsonNode node = mapper.readTree(json);
+            assertEquals(0, node.get("result").get("data").get(0).asInt());
+        }
+
         final HttpPost httppost3 = new HttpPost(TestClientFactory.createURLString());
         httppost3.setHeader(HttpHeaders.CONTENT_TYPE, SerTokens.MIME_JSON);
         httppost3.setHeader(HttpHeaders.ACCEPT, SerTokens.MIME_GRAPHSON_V3D0);