This is an automated email from the ASF dual-hosted git repository.

xiazcy pushed a commit to branch multi-label-experiment
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 27da3669c7d134d4c46e4bbb4deb856542389bf7
Author: Yang Xia <[email protected]>
AuthorDate: Wed Jun 17 07:49:19 2026 -0700

    Add cardinality
---
 .../grammar/DefaultGremlinBaseVisitor.java         |   4 -
 .../language/grammar/TraversalMethodVisitor.java   |  19 ---
 .../grammar/TraversalSourceSpawnMethodVisitor.java |  26 +---
 .../process/traversal/step/map/AddVertexStep.java  |  15 +-
 .../apache/tinkerpop/gremlin/structure/Graph.java  |  44 ++++++
 .../gremlin/structure/LabelCardinality.java        | 153 +++++++++++++++++++
 .../structure/io/binary/types/EdgeSerializer.java  |  15 +-
 .../structure/io/binary/types/GraphSerializer.java |   6 +-
 .../io/binary/types/VertexSerializer.java          |   6 +-
 .../structure/io/graphml/GraphMLWriter.java        |   6 +-
 .../io/graphson/GraphSONSerializersV1.java         |   8 +-
 .../io/graphson/GraphSONSerializersV2.java         |   8 +-
 .../io/graphson/GraphSONSerializersV3.java         |   8 +-
 .../structure/io/gryo/GryoSerializersV3.java       |  10 +-
 .../gremlin/structure/util/star/StarGraph.java     |  14 +-
 .../Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs |   8 +-
 gremlin-go/driver/cucumber/gremlin.go              |   8 +-
 .../gremlin-javascript/test/cucumber/gremlin.js    |   8 +-
 gremlin-language/src/main/antlr4/Gremlin.g4        |   2 -
 .../src/main/python/tests/feature/gremlin.py       |   8 +-
 .../gremlin/language/translator/translations.json  | 170 +++------------------
 .../gremlin/test/features/map/AddEdge.feature      |  32 ----
 .../gremlin/test/features/map/MergeVertex.feature  |   2 +-
 .../test/features/sideEffect/AddLabel.feature      |   4 +-
 .../test/features/sideEffect/DropLabel.feature     |  18 +--
 .../ser/binary/TypeSerializerFailureTests.java     |   7 +-
 .../tinkergraph/structure/AbstractTinkerGraph.java |  27 ++++
 .../gremlin/tinkergraph/structure/TinkerEdge.java  |  38 +++--
 .../gremlin/tinkergraph/structure/TinkerGraph.java |  10 +-
 .../structure/TinkerTransactionGraph.java          |  10 +-
 .../tinkergraph/structure/TinkerVertex.java        |  65 ++++++--
 .../traversal/step/map/MergeVMultiLabelTest.java   |   5 +-
 .../step/sideEffect/LabelMutationPropertyTest.java |   7 +-
 .../step/sideEffect/LabelMutationStepTest.java     |  13 +-
 .../structure/TinkerVertexMultiLabelTest.java      |  24 +--
 35 files changed, 438 insertions(+), 370 deletions(-)

diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
index 5257be977a..a3cc037253 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/DefaultGremlinBaseVisitor.java
@@ -167,10 +167,6 @@ public class DefaultGremlinBaseVisitor<T> extends 
AbstractParseTreeVisitor<T> im
         * {@inheritDoc}
         */
        @Override public T visitTraversalMethod_addE_String(final 
GremlinParser.TraversalMethod_addE_StringContext ctx) { notImplemented(ctx); 
return null; }
-       /**
-        * {@inheritDoc}
-        */
-       @Override public T visitTraversalMethod_addE_StringVarargs(final 
GremlinParser.TraversalMethod_addE_StringVarargsContext ctx) { 
notImplemented(ctx); return null; }
        /**
         * {@inheritDoc}
         */
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
index cc65794ed6..cf99aeb3e5 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalMethodVisitor.java
@@ -205,25 +205,6 @@ public class TraversalMethodVisitor extends 
TraversalRootVisitor<GraphTraversal>
         }
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public GraphTraversal visitTraversalMethod_addE_StringVarargs(final 
GremlinParser.TraversalMethod_addE_StringVarargsContext ctx) {
-        final List<GremlinParser.StringArgumentContext> args = 
ctx.stringArgument();
-        final Object firstLiteralOrVar = 
antlr.argumentVisitor.visitStringArgument(args.get(0));
-        final String firstLabel = firstLiteralOrVar instanceof String ? 
(String) firstLiteralOrVar : ((GValue<String>) firstLiteralOrVar).get();
-        final Object secondLiteralOrVar = 
antlr.argumentVisitor.visitStringArgument(args.get(1));
-        final String secondLabel = secondLiteralOrVar instanceof String ? 
(String) secondLiteralOrVar : ((GValue<String>) secondLiteralOrVar).get();
-
-        final String[] moreLabels = new String[args.size() - 2];
-        for (int i = 2; i < args.size(); i++) {
-            final Object literalOrVar = 
antlr.argumentVisitor.visitStringArgument(args.get(i));
-            moreLabels[i - 2] = literalOrVar instanceof String ? (String) 
literalOrVar : ((GValue<String>) literalOrVar).get();
-        }
-        return this.graphTraversal.addE(firstLabel, secondLabel, moreLabels);
-    }
-
     /**
      * {@inheritDoc}
      */
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
index 5ce9b41c09..5ce311697f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/language/grammar/TraversalSourceSpawnMethodVisitor.java
@@ -57,27 +57,13 @@ public class TraversalSourceSpawnMethodVisitor extends 
DefaultGremlinBaseVisitor
      */
     @Override
     public GraphTraversal visitTraversalSourceSpawnMethod_addE(final 
GremlinParser.TraversalSourceSpawnMethod_addEContext ctx) {
-        final List<GremlinParser.StringArgumentContext> stringArgs = 
ctx.stringArgument();
-        if (stringArgs != null && !stringArgs.isEmpty()) {
-            if (stringArgs.size() == 1) {
-                final Object literalOrVar = 
antlr.argumentVisitor.visitStringArgument(stringArgs.get(0));
-                if (GValue.valueInstanceOf(literalOrVar, String.class)) {
-                    return this.traversalSource.addE((GValue<String>) 
literalOrVar);
-                } else {
-                    return this.traversalSource.addE((String) literalOrVar);
-                }
+        final GremlinParser.StringArgumentContext stringArg = 
ctx.stringArgument();
+        if (stringArg != null) {
+            final Object literalOrVar = 
antlr.argumentVisitor.visitStringArgument(stringArg);
+            if (GValue.valueInstanceOf(literalOrVar, String.class)) {
+                return this.traversalSource.addE((GValue<String>) 
literalOrVar);
             } else {
-                // Multi-label: addE("a", "b", ...)
-                final Object firstLiteralOrVar = 
antlr.argumentVisitor.visitStringArgument(stringArgs.get(0));
-                final String firstLabel = firstLiteralOrVar instanceof String 
? (String) firstLiteralOrVar : ((GValue<String>) firstLiteralOrVar).get();
-                final Object secondLiteralOrVar = 
antlr.argumentVisitor.visitStringArgument(stringArgs.get(1));
-                final String secondLabel = secondLiteralOrVar instanceof 
String ? (String) secondLiteralOrVar : ((GValue<String>) 
secondLiteralOrVar).get();
-                final String[] moreLabels = new String[stringArgs.size() - 2];
-                for (int i = 2; i < stringArgs.size(); i++) {
-                    final Object literalOrVar = 
antlr.argumentVisitor.visitStringArgument(stringArgs.get(i));
-                    moreLabels[i - 2] = literalOrVar instanceof String ? 
(String) literalOrVar : ((GValue<String>) literalOrVar).get();
-                }
-                return this.traversalSource.addE(firstLabel, secondLabel, 
moreLabels);
+                return this.traversalSource.addE((String) literalOrVar);
             }
         } else if (ctx.nestedTraversal() != null) {
             return 
this.traversalSource.addE(anonymousVisitor.visitNestedTraversal(ctx.nestedTraversal()));
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
index 4c2b505b53..8a48d1728b 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
@@ -49,24 +49,27 @@ public class AddVertexStep<S> extends ScalarMapStep<S, 
Vertex> implements AddVer
 
     public AddVertexStep(final Traversal.Admin traversal, final String label) {
         super(traversal);
-        this.internalParameters.set(this, T.label, null == label ? 
Vertex.DEFAULT_LABEL : label);
+        if (label != null) {
+            this.internalParameters.set(this, T.label, label);
+        }
         userProvidedLabel = label != null;
     }
 
     public AddVertexStep(final Traversal.Admin traversal, final 
Traversal.Admin<S,String> vertexLabelTraversal) {
         super(traversal);
-        this.internalParameters.set(this, T.label, null == 
vertexLabelTraversal ? Vertex.DEFAULT_LABEL : vertexLabelTraversal);
+        if (vertexLabelTraversal != null) {
+            this.internalParameters.set(this, T.label, vertexLabelTraversal);
+        }
         userProvidedLabel = vertexLabelTraversal != null;
     }
 
     public AddVertexStep(final Traversal.Admin traversal, final Set<String> 
labels) {
         super(traversal);
-        if (labels == null || labels.isEmpty()) {
-            this.internalParameters.set(this, T.label, Vertex.DEFAULT_LABEL);
-            userProvidedLabel = false;
-        } else {
+        if (labels != null && !labels.isEmpty()) {
             this.internalParameters.set(this, T.label, labels);
             userProvidedLabel = true;
+        } else {
+            userProvidedLabel = false;
         }
     }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
index 3f9f246297..fe6291e616 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/Graph.java
@@ -655,6 +655,28 @@ public interface Graph extends AutoCloseable, Host {
                 return new VertexPropertyFeatures() {
                 };
             }
+
+            /**
+             * Gets the {@link LabelCardinality} for vertices in this graph. 
Defines how many labels
+             * a vertex can have and whether labels are mutable.
+             *
+             * @return the label cardinality for vertices, defaulting to 
{@link LabelCardinality#ZERO_OR_MORE}
+             * @since 4.0.0
+             */
+            default LabelCardinality getLabelCardinality() {
+                return LabelCardinality.ZERO_OR_MORE;
+            }
+
+            /**
+             * Gets the default label returned for vertices with no explicit 
labels when the cardinality
+             * requires at least one label ({@link LabelCardinality#ONE} or 
{@link LabelCardinality#ONE_OR_MORE}).
+             *
+             * @return the default vertex label, typically {@link 
Vertex#DEFAULT_LABEL}
+             * @since 4.0.0
+             */
+            default String getDefaultLabel() {
+                return Vertex.DEFAULT_LABEL;
+            }
         }
 
         /**
@@ -703,6 +725,28 @@ public interface Graph extends AutoCloseable, Host {
                 return new EdgePropertyFeatures() {
                 };
             }
+
+            /**
+             * Gets the {@link LabelCardinality} for edges in this graph. 
Defines how many labels
+             * an edge can have and whether labels are mutable.
+             *
+             * @return the label cardinality for edges, defaulting to {@link 
LabelCardinality#ZERO_OR_ONE}
+             * @since 4.0.0
+             */
+            default LabelCardinality getLabelCardinality() {
+                return LabelCardinality.ZERO_OR_ONE;
+            }
+
+            /**
+             * Gets the default label returned for edges with no explicit 
labels when the cardinality
+             * requires at least one label ({@link LabelCardinality#ONE} or 
{@link LabelCardinality#ONE_OR_MORE}).
+             *
+             * @return the default edge label, typically {@link 
Edge#DEFAULT_LABEL}
+             * @since 4.0.0
+             */
+            default String getDefaultLabel() {
+                return Edge.DEFAULT_LABEL;
+            }
         }
 
         /**
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/LabelCardinality.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/LabelCardinality.java
new file mode 100644
index 0000000000..690fa75cef
--- /dev/null
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/LabelCardinality.java
@@ -0,0 +1,153 @@
+/*
+ * 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.structure;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Defines the label cardinality for graph elements (vertices and edges). 
Providers declare their
+ * supported cardinality via {@link Graph.Features} and use the validation 
methods to enforce
+ * label mutation constraints.
+ * <p>
+ * The four cardinality modes are:
+ * <ul>
+ *   <li>{@link #ONE} — Exactly one label, immutable (classic TinkerPop 3.x 
behavior)</li>
+ *   <li>{@link #ZERO_OR_ONE} — Zero or one label, mutable, droppable to 
zero</li>
+ *   <li>{@link #ONE_OR_MORE} — One or more labels, must always have at least 
one (virtual default fills when empty)</li>
+ *   <li>{@link #ZERO_OR_MORE} — Zero or more labels, fully flexible</li>
+ * </ul>
+ *
+ * @since 4.0.0
+ */
+public enum LabelCardinality {
+
+    /**
+     * Exactly one label, immutable. All mutation operations throw.
+     * This provides backward compatibility with TinkerPop 3.x single-label 
semantics.
+     */
+    ONE,
+
+    /**
+     * Zero or one label, mutable. The element can have at most one label at a 
time.
+     * To change the label, the existing one must be dropped first.
+     */
+    ZERO_OR_ONE,
+
+    /**
+     * One or more labels, mutable. The element must always have at least one 
label.
+     * When all explicit labels are removed, the provider's default label 
(e.g., "vertex" or "edge")
+     * is returned at read time as a virtual floor.
+     */
+    ONE_OR_MORE,
+
+    /**
+     * Zero or more labels, fully flexible. No constraints on the number of 
labels.
+     * Elements can have any number of labels including zero.
+     */
+    ZERO_OR_MORE;
+
+    /**
+     * Whether this cardinality allows multiple labels on an element 
simultaneously.
+     *
+     * @return {@code true} for {@link #ONE_OR_MORE} and {@link #ZERO_OR_MORE}
+     */
+    public boolean supportsMultiLabel() {
+        return this == ONE_OR_MORE || this == ZERO_OR_MORE;
+    }
+
+    /**
+     * Whether this cardinality allows an element to have zero labels.
+     *
+     * @return {@code true} for {@link #ZERO_OR_ONE} and {@link #ZERO_OR_MORE}
+     */
+    public boolean supportsZeroLabels() {
+        return this == ZERO_OR_ONE || this == ZERO_OR_MORE;
+    }
+
+    /**
+     * Whether this cardinality allows label mutation (addLabel/dropLabel).
+     *
+     * @return {@code true} for all modes except {@link #ONE}
+     */
+    public boolean supportsMutation() {
+        return this != ONE;
+    }
+
+    /**
+     * Validates that adding the specified labels would not violate this 
cardinality's constraints.
+     * Must be called BEFORE any mutation to ensure no invalid intermediate 
states.
+     *
+     * @param currentLabels the element's current label set
+     * @param label         the first label to add
+     * @param moreLabels    additional labels to add (varargs)
+     * @throws IllegalStateException if the addition would violate cardinality 
constraints
+     */
+    public void validateAdd(final Set<String> currentLabels, final String 
label, final String... moreLabels) {
+        if (!supportsMutation())
+            throw new IllegalStateException("Label mutation is not supported 
with cardinality " + this +
+                    ". Labels are immutable once assigned.");
+
+        if (!supportsMultiLabel()) {
+            // ZERO_OR_ONE: resulting set must have at most 1 element
+            // Fast path: single label + empty set → always valid
+            if (moreLabels.length == 0 && currentLabels.isEmpty())
+                return;
+
+            // Compute the resulting set size
+            final Set<String> resultSet = new HashSet<>(currentLabels);
+            resultSet.add(label);
+            for (final String l : moreLabels) {
+                resultSet.add(l);
+            }
+            if (resultSet.size() > 1)
+                throw new IllegalStateException("Cannot add label: would 
result in " + resultSet.size() +
+                        " labels but cardinality is " + this + ". Drop the 
existing label first.");
+        }
+    }
+
+    /**
+     * Validates that dropping a specific label would not violate this 
cardinality's constraints.
+     * For mutable cardinalities, dropping always succeeds (floor is applied 
at read time).
+     *
+     * @param currentLabels the element's current label set
+     * @param label         the label to drop
+     * @throws IllegalStateException if mutation is not supported (ONE mode)
+     */
+    public void validateDrop(final Set<String> currentLabels, final String 
label) {
+        if (!supportsMutation())
+            throw new IllegalStateException("Label mutation is not supported 
with cardinality " + this +
+                    ". Labels are immutable once assigned.");
+        // No floor validation needed — floor is applied at read time by the 
element's labels() method
+    }
+
+    /**
+     * Validates that dropping all labels would not violate this cardinality's 
constraints.
+     * For mutable cardinalities, dropping all always succeeds (floor is 
applied at read time).
+     *
+     * @param currentLabels the element's current label set
+     * @throws IllegalStateException if mutation is not supported (ONE mode)
+     */
+    public void validateDropAll(final Set<String> currentLabels) {
+        if (!supportsMutation())
+            throw new IllegalStateException("Label mutation is not supported 
with cardinality " + this +
+                    ". Labels are immutable once assigned.");
+        // Always succeeds for mutable cardinalities — floor applied at read 
time
+    }
+}
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java
index fe48d6f6ae..2f63384fcf 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/EdgeSerializer.java
@@ -100,26 +100,17 @@ public class EdgeSerializer extends 
SimpleTypeSerializer<Edge> {
         context.write(value.id(), buffer);
         // Write all edge labels as List<String> for multi-label support
         final Set<String> edgeLabels = value.labels();
-        if (edgeLabels == null || edgeLabels.isEmpty()) {
-            throw new IOException("Unexpected null or empty labels when 
nullable is false");
-        }
-        context.writeValue(new ArrayList<>(edgeLabels), buffer, false);
+        context.writeValue(edgeLabels == null ? new ArrayList<>() : new 
ArrayList<>(edgeLabels), buffer, false);
 
         context.write(value.inVertex().id(), buffer);
         // Write all inVertex labels as List<String> for multi-label support
         final Set<String> inVLabels = value.inVertex().labels();
-        if (inVLabels == null || inVLabels.isEmpty()) {
-            throw new IOException("Unexpected null or empty labels when 
nullable is false");
-        }
-        context.writeValue(new ArrayList<>(inVLabels), buffer, false);
+        context.writeValue(inVLabels == null ? new ArrayList<>() : new 
ArrayList<>(inVLabels), buffer, false);
 
         context.write(value.outVertex().id(), buffer);
         // Write all outVertex labels as List<String> for multi-label support
         final Set<String> outVLabels = value.outVertex().labels();
-        if (outVLabels == null || outVLabels.isEmpty()) {
-            throw new IOException("Unexpected null or empty labels when 
nullable is false");
-        }
-        context.writeValue(new ArrayList<>(outVLabels), buffer, false);
+        context.writeValue(outVLabels == null ? new ArrayList<>() : new 
ArrayList<>(outVLabels), buffer, false);
 
         // we don't serialize the parent Vertex for edges.
         context.write(null, buffer);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java
index 4138555dc1..62f5e2546c 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/GraphSerializer.java
@@ -135,7 +135,8 @@ public class GraphSerializer extends 
SimpleTypeSerializer<Graph> {
 
         context.write(vertex.id(), buffer);
         // serializing label as list here for now according to GraphBinaryV4
-        context.writeValue(Collections.singletonList(vertex.label()), buffer, 
false);
+        final String vLabel = vertex.label();
+        context.writeValue(vLabel == null ? Collections.emptyList() : 
Collections.singletonList(vLabel), buffer, false);
         context.writeValue(vertexProperties.size(), buffer, false);
 
         for (VertexProperty<Object> vp : vertexProperties) {
@@ -154,7 +155,8 @@ public class GraphSerializer extends 
SimpleTypeSerializer<Graph> {
     private void writeEdge(Buffer buffer, GraphBinaryWriter context, Edge 
edge) throws IOException {
         context.write(edge.id(), buffer);
         // serializing label as list here for now according to GraphBinaryV4
-        context.writeValue(Collections.singletonList(edge.label()), buffer, 
false);
+        final String eLabel = edge.label();
+        context.writeValue(eLabel == null ? Collections.emptyList() : 
Collections.singletonList(eLabel), buffer, false);
 
         context.write(edge.inVertex().id(), buffer);
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java
index ce6befecba..f5074cc643 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/binary/types/VertexSerializer.java
@@ -72,11 +72,9 @@ public class VertexSerializer extends 
SimpleTypeSerializer<Vertex> {
     protected void writeValue(final Vertex value, final Buffer buffer, final 
GraphBinaryWriter context) throws IOException {
         context.write(value.id(), buffer);
         // Write all labels as List<String> for multi-label support.
+        // Empty list is valid for zero-label elements (ZERO_OR_MORE / 
ZERO_OR_ONE cardinality).
         final java.util.Set<String> labels = value.labels();
-        if (labels == null || labels.isEmpty()) {
-            throw new IOException("Unexpected null or empty labels when 
nullable is false");
-        }
-        context.writeValue(new ArrayList<>(labels), buffer, false);
+        context.writeValue(labels == null ? new ArrayList<>() : new 
ArrayList<>(labels), buffer, false);
         if (value instanceof ReferenceVertex) {
             context.write(null, buffer);
         }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
index cae0f9c987..0c75805f3a 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphml/GraphMLWriter.java
@@ -266,7 +266,7 @@ public final class GraphMLWriter implements GraphWriter {
 
                     writer.writeStartElement(GraphMLTokens.DATA);
                     writer.writeAttribute(GraphMLTokens.KEY, 
this.edgeLabelKey);
-                    writer.writeCharacters(edge.label());
+                    writer.writeCharacters(edge.label() == null ? "" : 
edge.label());
                     writer.writeEndElement();
 
                     final List<String> keys = new ArrayList<>(edge.keys());
@@ -296,7 +296,7 @@ public final class GraphMLWriter implements GraphWriter {
 
                     writer.writeStartElement(GraphMLTokens.DATA);
                     writer.writeAttribute(GraphMLTokens.KEY, 
this.edgeLabelKey);
-                    writer.writeCharacters(edge.label());
+                    writer.writeCharacters(edge.label() == null ? "" : 
edge.label());
                     writer.writeEndElement();
 
                     for (String key : edge.keys()) {
@@ -328,7 +328,7 @@ public final class GraphMLWriter implements GraphWriter {
 
             writer.writeStartElement(GraphMLTokens.DATA);
             writer.writeAttribute(GraphMLTokens.KEY, this.vertexLabelKey);
-            writer.writeCharacters(vertex.label());
+            writer.writeCharacters(vertex.label() == null ? "" : 
vertex.label());
             writer.writeEndElement();
 
             for (String key : keys) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java
index 4841b482b4..32a49a34c2 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV1.java
@@ -140,10 +140,10 @@ final class GraphSONSerializersV1 {
             if (typeSerializer != null) 
jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
             GraphSONUtil.writeWithType(GraphSONTokens.ID, edge.id(), 
jsonGenerator, serializerProvider, typeSerializer);
 
-            jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label());
+            jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label() 
== null ? "" : edge.label());
             jsonGenerator.writeStringField(GraphSONTokens.TYPE, 
GraphSONTokens.EDGE);
-            jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, 
edge.inVertex().label());
-            jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, 
edge.outVertex().label());
+            jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, 
edge.inVertex().label() == null ? "" : edge.inVertex().label());
+            jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, 
edge.outVertex().label() == null ? "" : edge.outVertex().label());
             GraphSONUtil.writeWithType(GraphSONTokens.IN, 
edge.inVertex().id(), jsonGenerator, serializerProvider, typeSerializer);
             GraphSONUtil.writeWithType(GraphSONTokens.OUT, 
edge.outVertex().id(), jsonGenerator, serializerProvider, typeSerializer);
             writeProperties(edge, jsonGenerator, serializerProvider, 
typeSerializer);
@@ -196,7 +196,7 @@ final class GraphSONSerializersV1 {
             jsonGenerator.writeStartObject();
             if (typeSerializer != null) 
jsonGenerator.writeStringField(GraphSONTokens.CLASS, HashMap.class.getName());
             GraphSONUtil.writeWithType(GraphSONTokens.ID, vertex.id(), 
jsonGenerator, serializerProvider, typeSerializer);
-            jsonGenerator.writeStringField(GraphSONTokens.LABEL, 
vertex.label());
+            jsonGenerator.writeStringField(GraphSONTokens.LABEL, 
vertex.label() == null ? "" : vertex.label());
             jsonGenerator.writeStringField(GraphSONTokens.TYPE, 
GraphSONTokens.VERTEX);
             writeProperties(vertex, jsonGenerator, serializerProvider, 
typeSerializer);
             jsonGenerator.writeEndObject();
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java
index 8b52323c94..871569d2a4 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV2.java
@@ -101,7 +101,7 @@ class GraphSONSerializersV2 {
             jsonGenerator.writeStartObject();
 
             jsonGenerator.writeObjectField(GraphSONTokens.ID, vertex.id());
-            jsonGenerator.writeStringField(GraphSONTokens.LABEL, 
vertex.label());
+            jsonGenerator.writeStringField(GraphSONTokens.LABEL, 
vertex.label() == null ? "" : vertex.label());
             writeProperties(vertex, jsonGenerator);
 
             jsonGenerator.writeEndObject();
@@ -150,9 +150,9 @@ class GraphSONSerializersV2 {
             jsonGenerator.writeStartObject();
 
             jsonGenerator.writeObjectField(GraphSONTokens.ID, edge.id());
-            jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label());
-            jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, 
edge.inVertex().label());
-            jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, 
edge.outVertex().label());
+            jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label() 
== null ? "" : edge.label());
+            jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, 
edge.inVertex().label() == null ? "" : edge.inVertex().label());
+            jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, 
edge.outVertex().label() == null ? "" : edge.outVertex().label());
             jsonGenerator.writeObjectField(GraphSONTokens.IN, 
edge.inVertex().id());
             jsonGenerator.writeObjectField(GraphSONTokens.OUT, 
edge.outVertex().id());
             writeProperties(edge, jsonGenerator);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java
index 6df9141f5b..c9f2520556 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/graphson/GraphSONSerializersV3.java
@@ -101,7 +101,7 @@ class GraphSONSerializersV3 {
             jsonGenerator.writeStartObject();
 
             jsonGenerator.writeObjectField(GraphSONTokens.ID, vertex.id());
-            jsonGenerator.writeStringField(GraphSONTokens.LABEL, 
vertex.label());
+            jsonGenerator.writeStringField(GraphSONTokens.LABEL, 
vertex.label() == null ? "" : vertex.label());
             writeTypeForGraphObjectIfUntyped(jsonGenerator, typeInfo, 
GraphSONTokens.VERTEX);
             writeProperties(vertex, jsonGenerator, serializerProvider);
 
@@ -161,10 +161,10 @@ class GraphSONSerializersV3 {
             jsonGenerator.writeStartObject();
 
             jsonGenerator.writeObjectField(GraphSONTokens.ID, edge.id());
-            jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label());
+            jsonGenerator.writeStringField(GraphSONTokens.LABEL, edge.label() 
== null ? "" : edge.label());
             writeTypeForGraphObjectIfUntyped(jsonGenerator, typeInfo, 
GraphSONTokens.EDGE);
-            jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, 
edge.inVertex().label());
-            jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, 
edge.outVertex().label());
+            jsonGenerator.writeStringField(GraphSONTokens.IN_LABEL, 
edge.inVertex().label() == null ? "" : edge.inVertex().label());
+            jsonGenerator.writeStringField(GraphSONTokens.OUT_LABEL, 
edge.outVertex().label() == null ? "" : edge.outVertex().label());
             jsonGenerator.writeObjectField(GraphSONTokens.IN, 
edge.inVertex().id());
             jsonGenerator.writeObjectField(GraphSONTokens.OUT, 
edge.outVertex().id());
             writeProperties(edge, jsonGenerator);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java
index 5a0beec2ae..e53f1aacef 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/io/gryo/GryoSerializersV3.java
@@ -74,7 +74,7 @@ public final class GryoSerializersV3 {
         @Override
         public <O extends OutputShim> void write(final KryoShim<?, O> kryo, 
final O output, final Edge edge) {
             kryo.writeClassAndObject(output, edge.id());
-            output.writeString(edge.label());
+            output.writeString(edge.label() == null ? "" : edge.label());
             kryo.writeClassAndObject(output, edge.inVertex().id());
 
             // temporary try/catch perhaps? need this to get 
SparkSingleIterationStrategyTest to work. Trying to grab
@@ -84,7 +84,8 @@ public final class GryoSerializersV3 {
             //
             // ghetto
             try {
-                output.writeString(edge.inVertex().label());
+                final String inLabel = edge.inVertex().label();
+                output.writeString(inLabel == null ? Vertex.DEFAULT_LABEL : 
inLabel);
             } catch (Exception ex) {
                 output.writeString(Vertex.DEFAULT_LABEL);
             }
@@ -93,7 +94,8 @@ public final class GryoSerializersV3 {
 
             // same nonsense as above for a default label
             try {
-                output.writeString(edge.outVertex().label());
+                final String outLabel = edge.outVertex().label();
+                output.writeString(outLabel == null ? Vertex.DEFAULT_LABEL : 
outLabel);
             } catch (Exception ex) {
                 output.writeString(Vertex.DEFAULT_LABEL);
             }
@@ -132,7 +134,7 @@ public final class GryoSerializersV3 {
         @Override
         public <O extends OutputShim> void write(final KryoShim<?, O> kryo, 
final O output, final Vertex vertex) {
             kryo.writeClassAndObject(output, vertex.id());
-            output.writeString(vertex.label());
+            output.writeString(vertex.label() == null ? "" : vertex.label());
 
             final Iterator<? extends VertexProperty> properties = 
vertex.properties();
             output.writeBoolean(properties.hasNext());
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
index 1981a3257b..30c5cb9066 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/util/star/StarGraph.java
@@ -205,7 +205,13 @@ public final class StarGraph implements Graph, 
Serializable {
         if (vertex instanceof StarVertex) return (StarGraph) vertex.graph();
         // else convert to a star graph
         final StarGraph starGraph = new StarGraph();
-        final StarVertex starVertex = (StarVertex) starGraph.addVertex(T.id, 
vertex.id(), T.label, vertex.label());
+        final String vertexLabel = vertex.label();
+        final StarVertex starVertex;
+        if (vertexLabel != null) {
+            starVertex = (StarVertex) starGraph.addVertex(T.id, vertex.id(), 
T.label, vertexLabel);
+        } else {
+            starVertex = (StarVertex) starGraph.addVertex(T.id, vertex.id());
+        }
 
         // Copy multi-labels from source vertex
         final Set<String> srcLabels = vertex.labels();
@@ -221,7 +227,8 @@ public final class StarGraph implements Graph, Serializable 
{
                 vp.properties().forEachRemaining(p -> 
starVertexProperty.property(p.key(), p.value()));
         });
         vertex.edges(Direction.IN).forEachRemaining(edge -> {
-            final Edge starEdge = starVertex.addInEdge(edge.label(), 
starGraph.addVertex(T.id, edge.outVertex().id()), T.id, edge.id());
+            final String edgeLabel = edge.label() == null ? Edge.DEFAULT_LABEL 
: edge.label();
+            final Edge starEdge = starVertex.addInEdge(edgeLabel, 
starGraph.addVertex(T.id, edge.outVertex().id()), T.id, edge.id());
             edge.properties().forEachRemaining(p -> starEdge.property(p.key(), 
p.value()));
             final Set<String> edgeSrcLabels = edge.labels();
             if (edgeSrcLabels.size() > 1) {
@@ -230,7 +237,8 @@ public final class StarGraph implements Graph, Serializable 
{
         });
 
         vertex.edges(Direction.OUT).forEachRemaining(edge -> {
-            final Edge starEdge = starVertex.addOutEdge(edge.label(), 
starGraph.addVertex(T.id, edge.inVertex().id()), T.id, edge.id());
+            final String edgeLabel = edge.label() == null ? Edge.DEFAULT_LABEL 
: edge.label();
+            final Edge starEdge = starVertex.addOutEdge(edgeLabel, 
starGraph.addVertex(T.id, edge.inVertex().id()), T.id, edge.id());
             edge.properties().forEachRemaining(p -> starEdge.property(p.key(), 
p.value()));
             final Set<String> edgeSrcLabels = edge.labels();
             if (edgeSrcLabels.size() > 1) {
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs 
b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
index 6e19a2d5e1..e2b0f2b16b 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Gremlin.cs
@@ -921,8 +921,6 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                
{"g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 
29).AddV((string) "person").Property("name", "vadas").Property("age", 27), 
(g,p) =>g.Union<object>(__.AddE((string) p["xx1"]).Property("weight", 
1).From(__.V().Has("name", "marko")).To(__.V().Has("name", "vadas"))), (g,p) 
=>g.E( [...]
                
{"g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 
29).AddV((string) "person").Property("name", "vadas").Property("age", 27), 
(g,p) =>g.AddE((string) "edge").From(__.V().Has("name", 
"marko")).To(__.V().Has("name", "vadas")).Property("weight", 0.5).With(" [...]
                
{"g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX",
 new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 
29).AddV((string) "person").Property("name", "vadas").Property("age", 27), 
(g,p) =>g.AddE((string) "knows").From(__.V().Has("name", 
"marko")).To(__.V().Has("name", "vadas")).Property("weight", 0.5).Add [...]
-               {"g_addEXa_bX_from_V_to_V_labels_fold", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").AddV((string) 
"person").Property("name", "josh"), (g,p) =>g.AddE((string) "knows", (string) 
"trusts").From(__.V().Has("name", "marko")).To(__.V().Has("name", 
"josh")).Labels().Fold(), (g,p) =>g.E().HasLabel("knows"), (g,p) 
=>g.E().HasLabel("trusts")}}, 
-               {"g_addEXa_b_cX_from_V_to_V_labels_count", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").AddV((string) 
"person").Property("name", "josh"), (g,p) =>g.AddE((string) "a", (string) "b", 
(string) "c").From(__.V().Has("name", "marko")).To(__.V().Has("name", 
"josh")).Labels().Count()}}, 
                
{"g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX", 
new List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 
29).As("marko").AddV((string) "person").Property("name", 
"vadas").Property("age", 27).As("vadas").AddV((string) 
"software").Property("name", "lop").Property("lang", 
"java").As("lop").AddV((string) "person").Property("name", 
"josh").Property("age [...]
                {"g_V_addVXanimalX_propertyXage_0X", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 
29).As("marko").AddV((string) "person").Property("name", 
"vadas").Property("age", 27).As("vadas").AddV((string) 
"software").Property("name", "lop").Property("lang", 
"java").As("lop").AddV((string) "person").Property("name", 
"josh").Property("age", 32).As("josh").AddV((string) "softwar [...]
                {"g_V_addVXanimalvarX_propertyXage_0varX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko").Property("age", 
29).As("marko").AddV((string) "person").Property("name", 
"vadas").Property("age", 27).As("vadas").AddV((string) 
"software").Property("name", "lop").Property("lang", 
"java").As("lop").AddV((string) "person").Property("name", 
"josh").Property("age", 32).As("josh").AddV((string) "s [...]
@@ -1996,7 +1994,7 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                
{"g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", "marko"), (g,p) 
=>g.V().HasLabel("person").Has("name", 
"marko").AddLabel("employee").Labels().Fold(), (g,p) 
=>g.V().HasLabel("person").HasLabel("employee")}}, 
                {"g_V_addLabelXa_bX_labels_count", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person"), (g,p) =>g.V().AddLabel("a", 
"b").Labels().Count()}}, 
                {"g_V_addLabelXexistingX_labels_count", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person"), (g,p) 
=>g.V().AddLabel("person").Labels().Count()}}, 
-               {"g_E_addLabelXfriendX_labels_fold", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", 
"marko").As("a").AddV((string) "person").Property("name", 
"josh").As("b").AddE((string) "knows").From("a").To("b"), (g,p) 
=>g.E().AddLabel("friend").Labels().Fold(), (g,p) =>g.E().HasLabel("knows"), 
(g,p) =>g.E().HasLabel("friend")}}, 
+               {"g_E_addLabelXfriendX_labels_fold", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").Property("name", 
"marko").As("a").AddV((string) "person").Property("name", 
"josh").As("b").AddE((string) "knows").From("a").To("b"), (g,p) 
=>g.E().AddLabel("friend").Labels().Fold()}}, 
                {"g_V_valueXnameX_aggregateXxX_capXxX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Values<object>("name").Aggregate("x").Cap<object>("x")}}, 
                {"g_V_aggregateXxX_byXnameX_capXxX", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Aggregate("x").By("name").Cap<object>("x")}}, 
                {"g_V_out_aggregateXaX_path", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.V().Out().Aggregate("a").Path()}}, 
@@ -2058,8 +2056,8 @@ namespace Gremlin.Net.IntegrationTest.Gherkin
                {"g_V_dropLabels_labels", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) "a", 
(string) "b"), (g,p) =>g.V().DropLabels().Labels()}}, 
                {"g_V_dropLabelXa_bX_labels", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "a", (string) "b", (string) "c"), (g,p) 
=>g.V().DropLabel("a", "b").Labels()}}, 
                {"g_V_dropLabels_defaultLabel", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person"), (g,p) =>g.V().DropLabels().Labels()}}, 
-               {"g_E_dropLabelXknowsX_labels", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").As("a").AddV((string) 
"person").As("b").AddE("knows", "trusts").From("a").To("b"), (g,p) 
=>g.E().DropLabel("knows").Labels().Fold(), (g,p) =>g.E().HasLabel("knows"), 
(g,p) =>g.E().HasLabel("trusts")}}, 
-               {"g_E_dropLabels_labels", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) 
"person").As("a").AddV((string) "person").As("b").AddE("knows", 
"trusts").From("a").To("b"), (g,p) =>g.E().DropLabels().Labels()}}, 
+               {"g_E_dropLabelXknowsX_labels", new 
List<Func<GraphTraversalSource, IDictionary<string, object>, ITraversal>> 
{(g,p) =>g.AddV((string) "person").As("a").AddV((string) 
"person").As("b").AddE((string) "knows").From("a").To("b"), (g,p) 
=>g.E().DropLabel("knows").Labels().Fold()}}, 
+               {"g_E_dropLabels_labels", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.AddV((string) 
"person").As("a").AddV((string) "person").As("b").AddE((string) 
"knows").From("a").To("b"), (g,p) =>g.E().DropLabels().Labels()}}, 
                {"g_V_fail", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fail()}}, 
                {"g_V_failXmsgX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) =>g.V().Fail("msg")}}, 
                {"g_V_unionXout_failX", new List<Func<GraphTraversalSource, 
IDictionary<string, object>, ITraversal>> {(g,p) 
=>g.V().Union<object>(__.Out(), __.Fail())}}, 
diff --git a/gremlin-go/driver/cucumber/gremlin.go 
b/gremlin-go/driver/cucumber/gremlin.go
index e44a411b01..5f5a2ea179 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -891,8 +891,6 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     
"g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").Property("age", 29).AddV("person").Property("name", 
"vadas").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.Union(gremlingo.T__.AddE(p["xx1"]).Property("weight", 1).From(grem [...]
     
"g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").Property("age", 29).AddV("person").Property("name", 
"vadas").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.AddE("edge").From(gremlingo.T__.V().Has(" [...]
     
"g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX":
 {func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").Property("age", 29).AddV("person").Property("name", 
"vadas").Property("age", 27)}, func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.AddE("knows").From(gremlingo.T__.V().Ha [...]
-    "g_addEXa_bX_from_V_to_V_labels_fold": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").AddV("person").Property("name", "josh")}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddE("knows", 
"trusts").From(gremlingo.T__.V().Has("name", 
"marko")).To(gremlingo.T__.V().Has("name", "josh")).Labels().Fold()}, func(g 
*gremlingo.GraphTraversal [...]
-    "g_addEXa_b_cX_from_V_to_V_labels_count": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").AddV("person").Property("name", "josh")}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddE("a", "b", 
"c").From(gremlingo.T__.V().Has("name", 
"marko")).To(gremlingo.T__.V().Has("name", "josh")).Labels().Count()}}, 
     
"g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX": 
{func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").Property("age", 29).As("marko").AddV("person").Property("name", 
"vadas").Property("age", 27).As("vadas").AddV("software").Property("name", 
"lop").Property("lang", "java").As("lop").AddV("person").Property("name", 
"josh").Property("age", 32).As("josh").AddV("software") [...]
     "g_V_addVXanimalX_propertyXage_0X": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").Property("age", 29).As("marko").AddV("person").Property("name", 
"vadas").Property("age", 27).As("vadas").AddV("software").Property("name", 
"lop").Property("lang", "java").As("lop").AddV("person").Property("name", 
"josh").Property("age", 32).As("josh").AddV("software").Property("name", 
"ripple").Property("la [...]
     "g_V_addVXanimalvarX_propertyXage_0varX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").Property("age", 29).As("marko").AddV("person").Property("name", 
"vadas").Property("age", 27).As("vadas").AddV("software").Property("name", 
"lop").Property("lang", "java").As("lop").AddV("person").Property("name", 
"josh").Property("age", 32).As("josh").AddV("software").Property("name", 
"ripple").Proper [...]
@@ -1966,7 +1964,7 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", "marko")}, 
func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().HasLabel("person").Has("name", 
"marko").AddLabel("employee").Labels().Fold()}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal [...]
     "g_V_addLabelXa_bX_labels_count": {func(g *gremlingo.GraphTraversalSource, 
p map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person")}, 
func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().AddLabel("a", "b").Labels().Count()}}, 
     "g_V_addLabelXexistingX_labels_count": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person")}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().AddLabel("person").Labels().Count()}}, 
-    "g_E_addLabelXfriendX_labels_fold": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").As("a").AddV("person").Property("name", 
"josh").As("b").AddE("knows").From("a").To("b")}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E().AddLabel("friend").Labels().Fold()}, 
func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) *gremling 
[...]
+    "g_E_addLabelXfriendX_labels_fold": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.AddV("person").Property("name", 
"marko").As("a").AddV("person").Property("name", 
"josh").As("b").AddE("knows").From("a").To("b")}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E().AddLabel("friend").Labels().Fold()}}, 
     "g_V_valueXnameX_aggregateXxX_capXxX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return 
g.V().Values("name").Aggregate("x").Cap("x")}}, 
     "g_V_aggregateXxX_byXnameX_capXxX": {func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().Aggregate("x").By("name").Cap("x")}}, 
     "g_V_out_aggregateXaX_path": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Out().Aggregate("a").Path()}}, 
@@ -2028,8 +2026,8 @@ var translationMap = map[string][]func(g 
*gremlingo.GraphTraversalSource, p map[
     "g_V_dropLabels_labels": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("a", "b")}, 
func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().DropLabels().Labels()}}, 
     "g_V_dropLabelXa_bX_labels": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("a", "b", 
"c")}, func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().DropLabel("a", "b").Labels()}}, 
     "g_V_dropLabels_defaultLabel": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.AddV("person")}, 
func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.V().DropLabels().Labels()}}, 
-    "g_E_dropLabelXknowsX_labels": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.AddV("person").As("a").AddV("person").As("b").AddE("knows", 
"trusts").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.E().DropLabel("knows").Labels().Fold()}, func(g 
*gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E().HasLabel("knows [...]
-    "g_E_dropLabels_labels": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.AddV("person").As("a").AddV("person").As("b").AddE("knows", 
"trusts").From("a").To("b")}, func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.E().DropLabels().Labels()}}, 
+    "g_E_dropLabelXknowsX_labels": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.AddV("person").As("a").AddV("person").As("b").AddE("knows").From("a").To("b")},
 func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E().DropLabel("knows").Labels().Fold()}}, 
+    "g_E_dropLabels_labels": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.AddV("person").As("a").AddV("person").As("b").AddE("knows").From("a").To("b")},
 func(g *gremlingo.GraphTraversalSource, p map[string]interface{}) 
*gremlingo.GraphTraversal {return g.E().DropLabels().Labels()}}, 
     "g_V_fail": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Fail()}}, 
     "g_V_failXmsgX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Fail("msg")}}, 
     "g_V_unionXout_failX": {func(g *gremlingo.GraphTraversalSource, p 
map[string]interface{}) *gremlingo.GraphTraversal {return 
g.V().Union(gremlingo.T__.Out(), gremlingo.T__.Fail())}}, 
diff --git a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js 
b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
index b0ff76c57d..9893904988 100644
--- a/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
+++ b/gremlin-js/gremlin-javascript/test/cucumber/gremlin.js
@@ -922,8 +922,6 @@ const gremlins = {
     
g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX:
 [function({g, xx1}) { return g.addV("person").property("name", 
"marko").property("age", 29).addV("person").property("name", 
"vadas").property("age", 27) }, function({g, xx1}) { return 
g.union(__.addE(xx1).property("weight", 1).from_(__.V().has("name", 
"marko")).to(__.V().has("name", "vadas"))) }, function({g, xx1}) { return 
g.E().has("knows", "weight", 1) }], 
     
g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX:
 [function({g}) { return g.addV("person").property("name", 
"marko").property("age", 29).addV("person").property("name", 
"vadas").property("age", 27) }, function({g}) { return 
g.addE("edge").from_(__.V().has("name", "marko")).to(__.V().has("name", 
"vadas")).property("weight", 0.5).with_("key", "value").values("weight", "key") 
}], 
     
g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX:
 [function({g}) { return g.addV("person").property("name", 
"marko").property("age", 29).addV("person").property("name", 
"vadas").property("age", 27) }, function({g}) { return 
g.addE("knows").from_(__.V().has("name", "marko")).to(__.V().has("name", 
"vadas")).property("weight", 0.5).addE("knows").from_(__.V().has("name", 
"marko")) }], 
-    g_addEXa_bX_from_V_to_V_labels_fold: [function({g}) { return 
g.addV("person").property("name", "marko").addV("person").property("name", 
"josh") }, function({g}) { return g.addE("knows", 
"trusts").from_(__.V().has("name", "marko")).to(__.V().has("name", 
"josh")).labels().fold() }, function({g}) { return g.E().hasLabel("knows") }, 
function({g}) { return g.E().hasLabel("trusts") }], 
-    g_addEXa_b_cX_from_V_to_V_labels_count: [function({g}) { return 
g.addV("person").property("name", "marko").addV("person").property("name", 
"josh") }, function({g}) { return g.addE("a", "b", 
"c").from_(__.V().has("name", "marko")).to(__.V().has("name", 
"josh")).labels().count() }], 
     g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX: 
[function({g, vid1}) { return g.addV("person").property("name", 
"marko").property("age", 29).as("marko").addV("person").property("name", 
"vadas").property("age", 27).as("vadas").addV("software").property("name", 
"lop").property("lang", "java").as("lop").addV("person").property("name", 
"josh").property("age", 32).as("josh").addV("software").property("name", 
"ripple").property("lang", "java").as("ripple").addV("p [...]
     g_V_addVXanimalX_propertyXage_0X: [function({g}) { return 
g.addV("person").property("name", "marko").property("age", 
29).as("marko").addV("person").property("name", "vadas").property("age", 
27).as("vadas").addV("software").property("name", "lop").property("lang", 
"java").as("lop").addV("person").property("name", "josh").property("age", 
32).as("josh").addV("software").property("name", "ripple").property("lang", 
"java").as("ripple").addV("person").property("name", "peter").property("ag [...]
     g_V_addVXanimalvarX_propertyXage_0varX: [function({g, xx1, xx2}) { return 
g.addV("person").property("name", "marko").property("age", 
29).as("marko").addV("person").property("name", "vadas").property("age", 
27).as("vadas").addV("software").property("name", "lop").property("lang", 
"java").as("lop").addV("person").property("name", "josh").property("age", 
32).as("josh").addV("software").property("name", "ripple").property("lang", 
"java").as("ripple").addV("person").property("name", "pete [...]
@@ -1997,7 +1995,7 @@ const gremlins = {
     g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels: 
[function({g}) { return g.addV("person").property("name", "marko") }, 
function({g}) { return g.V().hasLabel("person").has("name", 
"marko").addLabel("employee").labels().fold() }, function({g}) { return 
g.V().hasLabel("person").hasLabel("employee") }], 
     g_V_addLabelXa_bX_labels_count: [function({g}) { return g.addV("person") 
}, function({g}) { return g.V().addLabel("a", "b").labels().count() }], 
     g_V_addLabelXexistingX_labels_count: [function({g}) { return 
g.addV("person") }, function({g}) { return 
g.V().addLabel("person").labels().count() }], 
-    g_E_addLabelXfriendX_labels_fold: [function({g}) { return 
g.addV("person").property("name", 
"marko").as("a").addV("person").property("name", 
"josh").as("b").addE("knows").from_("a").to("b") }, function({g}) { return 
g.E().addLabel("friend").labels().fold() }, function({g}) { return 
g.E().hasLabel("knows") }, function({g}) { return g.E().hasLabel("friend") }], 
+    g_E_addLabelXfriendX_labels_fold: [function({g}) { return 
g.addV("person").property("name", 
"marko").as("a").addV("person").property("name", 
"josh").as("b").addE("knows").from_("a").to("b") }, function({g}) { return 
g.E().addLabel("friend").labels().fold() }], 
     g_V_valueXnameX_aggregateXxX_capXxX: [function({g}) { return 
g.V().values("name").aggregate("x").cap("x") }], 
     g_V_aggregateXxX_byXnameX_capXxX: [function({g}) { return 
g.V().aggregate("x").by("name").cap("x") }], 
     g_V_out_aggregateXaX_path: [function({g}) { return 
g.V().out().aggregate("a").path() }], 
@@ -2059,8 +2057,8 @@ const gremlins = {
     g_V_dropLabels_labels: [function({g}) { return g.addV("a", "b") }, 
function({g}) { return g.V().dropLabels().labels() }], 
     g_V_dropLabelXa_bX_labels: [function({g}) { return g.addV("a", "b", "c") 
}, function({g}) { return g.V().dropLabel("a", "b").labels() }], 
     g_V_dropLabels_defaultLabel: [function({g}) { return g.addV("person") }, 
function({g}) { return g.V().dropLabels().labels() }], 
-    g_E_dropLabelXknowsX_labels: [function({g}) { return 
g.addV("person").as("a").addV("person").as("b").addE("knows", 
"trusts").from_("a").to("b") }, function({g}) { return 
g.E().dropLabel("knows").labels().fold() }, function({g}) { return 
g.E().hasLabel("knows") }, function({g}) { return g.E().hasLabel("trusts") }], 
-    g_E_dropLabels_labels: [function({g}) { return 
g.addV("person").as("a").addV("person").as("b").addE("knows", 
"trusts").from_("a").to("b") }, function({g}) { return 
g.E().dropLabels().labels() }], 
+    g_E_dropLabelXknowsX_labels: [function({g}) { return 
g.addV("person").as("a").addV("person").as("b").addE("knows").from_("a").to("b")
 }, function({g}) { return g.E().dropLabel("knows").labels().fold() }], 
+    g_E_dropLabels_labels: [function({g}) { return 
g.addV("person").as("a").addV("person").as("b").addE("knows").from_("a").to("b")
 }, function({g}) { return g.E().dropLabels().labels() }], 
     g_V_fail: [function({g}) { return g.V().fail() }], 
     g_V_failXmsgX: [function({g}) { return g.V().fail("msg") }], 
     g_V_unionXout_failX: [function({g}) { return g.V().union(__.out(), 
__.fail()) }], 
diff --git a/gremlin-language/src/main/antlr4/Gremlin.g4 
b/gremlin-language/src/main/antlr4/Gremlin.g4
index 2d7fa316a6..b60c62c6e8 100644
--- a/gremlin-language/src/main/antlr4/Gremlin.g4
+++ b/gremlin-language/src/main/antlr4/Gremlin.g4
@@ -113,7 +113,6 @@ traversalSourceSpawnMethod
 traversalSourceSpawnMethod_addE
     : K_ADDE LPAREN RPAREN
     | K_ADDE LPAREN stringArgument RPAREN
-    | K_ADDE LPAREN stringArgument COMMA stringArgument (COMMA 
stringArgument)* RPAREN
     | K_ADDE LPAREN nestedTraversal RPAREN
     ;
 
@@ -329,7 +328,6 @@ traversalMethod_E
 traversalMethod_addE
     : K_ADDE LPAREN RPAREN #traversalMethod_addE_Empty
     | K_ADDE LPAREN stringArgument RPAREN #traversalMethod_addE_String
-    | K_ADDE LPAREN stringArgument (COMMA stringArgument)+ RPAREN 
#traversalMethod_addE_StringVarargs
     | K_ADDE LPAREN nestedTraversal RPAREN #traversalMethod_addE_Traversal
     ;
 
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py 
b/gremlin-python/src/main/python/tests/feature/gremlin.py
index 3c9709c755..61c4af5360 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -896,8 +896,6 @@ world.gremlins = {
     
'g_unionXaddEXknowsvarXpropertyXweight_nullXfromXV_hasXname_markoXX_toXV_hasXname_vadasXXX':
 [(lambda g, xx1=None:g.add_v('person').property('name', 
'marko').property('age', 29).add_v('person').property('name', 
'vadas').property('age', 27)), (lambda g, 
xx1=None:g.union(__.add_e(xx1).property('weight', 1).from_(__.V().has('name', 
'marko')).to(__.V().has('name', 'vadas')))), (lambda g, 
xx1=None:g.E().has('knows', 'weight', 1))], 
     
'g_addEXedgeX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_withXkey_valueX_valuesXweight_keyX':
 [(lambda g:g.add_v('person').property('name', 'marko').property('age', 
29).add_v('person').property('name', 'vadas').property('age', 27)), (lambda 
g:g.add_e('edge').from_(__.V().has('name', 'marko')).to(__.V().has('name', 
'vadas')).property('weight', 0.5).with_('key', 'value').values('weight', 
'key'))], 
     
'g_addEXknowsX_fromXV_hasXname_markoXX_toXV_hasXname_vadasXX_propertyXweight_0_5X_addEXknowsX_fromXV_hasXname_markoXX':
 [(lambda g:g.add_v('person').property('name', 'marko').property('age', 
29).add_v('person').property('name', 'vadas').property('age', 27)), (lambda 
g:g.add_e('knows').from_(__.V().has('name', 'marko')).to(__.V().has('name', 
'vadas')).property('weight', 0.5).add_e('knows').from_(__.V().has('name', 
'marko')))], 
-    'g_addEXa_bX_from_V_to_V_labels_fold': [(lambda 
g:g.add_v('person').property('name', 'marko').add_v('person').property('name', 
'josh')), (lambda g:g.add_e('knows', 'trusts').from_(__.V().has('name', 
'marko')).to(__.V().has('name', 'josh')).labels().fold()), (lambda 
g:g.E().has_label('knows')), (lambda g:g.E().has_label('trusts'))], 
-    'g_addEXa_b_cX_from_V_to_V_labels_count': [(lambda 
g:g.add_v('person').property('name', 'marko').add_v('person').property('name', 
'josh')), (lambda g:g.add_e('a', 'b', 'c').from_(__.V().has('name', 
'marko')).to(__.V().has('name', 'josh')).labels().count())], 
     
'g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX': 
[(lambda g, vid1=None:g.add_v('person').property('name', 
'marko').property('age', 29).as_('marko').add_v('person').property('name', 
'vadas').property('age', 27).as_('vadas').add_v('software').property('name', 
'lop').property('lang', 'java').as_('lop').add_v('person').property('name', 
'josh').property('age', 32).as_('josh').add_v('software').property('name', 
'ripple').property('lang', 'java').as_('ripple').add [...]
     'g_V_addVXanimalX_propertyXage_0X': [(lambda 
g:g.add_v('person').property('name', 'marko').property('age', 
29).as_('marko').add_v('person').property('name', 'vadas').property('age', 
27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 
'java').as_('lop').add_v('person').property('name', 'josh').property('age', 
32).as_('josh').add_v('software').property('name', 'ripple').property('lang', 
'java').as_('ripple').add_v('person').property('name', 'peter').property('ag 
[...]
     'g_V_addVXanimalvarX_propertyXage_0varX': [(lambda g, 
xx1=None,xx2=None:g.add_v('person').property('name', 'marko').property('age', 
29).as_('marko').add_v('person').property('name', 'vadas').property('age', 
27).as_('vadas').add_v('software').property('name', 'lop').property('lang', 
'java').as_('lop').add_v('person').property('name', 'josh').property('age', 
32).as_('josh').add_v('software').property('name', 'ripple').property('lang', 
'java').as_('ripple').add_v('person').property('nam [...]
@@ -1971,7 +1969,7 @@ world.gremlins = {
     'g_V_hasLabelXpersonX_hasXname_markoX_addLabelXemployeeX_labels': [(lambda 
g:g.add_v('person').property('name', 'marko')), (lambda 
g:g.V().has_label('person').has('name', 
'marko').add_label('employee').labels().fold()), (lambda 
g:g.V().has_label('person').has_label('employee'))], 
     'g_V_addLabelXa_bX_labels_count': [(lambda g:g.add_v('person')), (lambda 
g:g.V().add_label('a', 'b').labels().count())], 
     'g_V_addLabelXexistingX_labels_count': [(lambda g:g.add_v('person')), 
(lambda g:g.V().add_label('person').labels().count())], 
-    'g_E_addLabelXfriendX_labels_fold': [(lambda 
g:g.add_v('person').property('name', 
'marko').as_('a').add_v('person').property('name', 
'josh').as_('b').add_e('knows').from_('a').to('b')), (lambda 
g:g.E().add_label('friend').labels().fold()), (lambda 
g:g.E().has_label('knows')), (lambda g:g.E().has_label('friend'))], 
+    'g_E_addLabelXfriendX_labels_fold': [(lambda 
g:g.add_v('person').property('name', 
'marko').as_('a').add_v('person').property('name', 
'josh').as_('b').add_e('knows').from_('a').to('b')), (lambda 
g:g.E().add_label('friend').labels().fold())], 
     'g_V_valueXnameX_aggregateXxX_capXxX': [(lambda 
g:g.V().values('name').aggregate('x').cap('x'))], 
     'g_V_aggregateXxX_byXnameX_capXxX': [(lambda 
g:g.V().aggregate('x').by('name').cap('x'))], 
     'g_V_out_aggregateXaX_path': [(lambda 
g:g.V().out().aggregate('a').path())], 
@@ -2033,8 +2031,8 @@ world.gremlins = {
     'g_V_dropLabels_labels': [(lambda g:g.add_v('a', 'b')), (lambda 
g:g.V().drop_labels().labels())], 
     'g_V_dropLabelXa_bX_labels': [(lambda g:g.add_v('a', 'b', 'c')), (lambda 
g:g.V().drop_label('a', 'b').labels())], 
     'g_V_dropLabels_defaultLabel': [(lambda g:g.add_v('person')), (lambda 
g:g.V().drop_labels().labels())], 
-    'g_E_dropLabelXknowsX_labels': [(lambda 
g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 
'trusts').from_('a').to('b')), (lambda 
g:g.E().drop_label('knows').labels().fold()), (lambda 
g:g.E().has_label('knows')), (lambda g:g.E().has_label('trusts'))], 
-    'g_E_dropLabels_labels': [(lambda 
g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 
'trusts').from_('a').to('b')), (lambda g:g.E().drop_labels().labels())], 
+    'g_E_dropLabelXknowsX_labels': [(lambda 
g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')),
 (lambda g:g.E().drop_label('knows').labels().fold())], 
+    'g_E_dropLabels_labels': [(lambda 
g:g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')),
 (lambda g:g.E().drop_labels().labels())], 
     'g_V_fail': [(lambda g:g.V().fail())], 
     'g_V_failXmsgX': [(lambda g:g.V().fail('msg'))], 
     'g_V_unionXout_failX': [(lambda g:g.V().union(__.out(), __.fail()))], 
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
index 7de3961add..db9e62435f 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/language/translator/translations.json
@@ -17831,88 +17831,6 @@
             }
         ]
     },
-    {
-        "scenario": "g_addEXa_bX_from_V_to_V_labels_fold",
-        "traversals": [
-            {
-                "original": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "language": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "canonical": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "anonymized": "g.addV(string0).property(string1, 
string2).addV(string0).property(string1, string3)",
-                "dotnet": "g.AddV((string) \"person\").Property(\"name\", 
\"marko\").AddV((string) \"person\").Property(\"name\", \"josh\")",
-                "go": "g.AddV(\"person\").Property(\"name\", 
\"marko\").AddV(\"person\").Property(\"name\", \"josh\")",
-                "groovy": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "java": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "javascript": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "python": "g.add_v('person').property('name', 
'marko').add_v('person').property('name', 'josh')"
-            },
-            {
-                "original": "g.addE(\"knows\", 
\"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().fold()",
-                "language": "g.addE(\"knows\", 
\"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().fold()",
-                "canonical": "g.addE(\"knows\", 
\"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().fold()",
-                "anonymized": "g.addE(string0, 
string1).from(__.V().has(string2, string3)).to(__.V().has(string2, 
string4)).labels().fold()",
-                "dotnet": "g.AddE((string) \"knows\", (string) 
\"trusts\").From(__.V().Has(\"name\", \"marko\")).To(__.V().Has(\"name\", 
\"josh\")).Labels().Fold()",
-                "go": "g.AddE(\"knows\", 
\"trusts\").From(gremlingo.T__.V().Has(\"name\", 
\"marko\")).To(gremlingo.T__.V().Has(\"name\", \"josh\")).Labels().Fold()",
-                "groovy": "g.addE(\"knows\", 
\"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().fold()",
-                "java": "g.addE(\"knows\", 
\"trusts\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().fold()",
-                "javascript": "g.addE(\"knows\", 
\"trusts\").from_(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().fold()",
-                "python": "g.add_e('knows', 'trusts').from_(__.V().has('name', 
'marko')).to(__.V().has('name', 'josh')).labels().fold()"
-            },
-            {
-                "original": "g.E().hasLabel(\"knows\")",
-                "language": "g.E().hasLabel(\"knows\")",
-                "canonical": "g.E().hasLabel(\"knows\")",
-                "anonymized": "g.E().hasLabel(string0)",
-                "dotnet": "g.E().HasLabel(\"knows\")",
-                "go": "g.E().HasLabel(\"knows\")",
-                "groovy": "g.E().hasLabel(\"knows\")",
-                "java": "g.E().hasLabel(\"knows\")",
-                "javascript": "g.E().hasLabel(\"knows\")",
-                "python": "g.E().has_label('knows')"
-            },
-            {
-                "original": "g.E().hasLabel(\"trusts\")",
-                "language": "g.E().hasLabel(\"trusts\")",
-                "canonical": "g.E().hasLabel(\"trusts\")",
-                "anonymized": "g.E().hasLabel(string0)",
-                "dotnet": "g.E().HasLabel(\"trusts\")",
-                "go": "g.E().HasLabel(\"trusts\")",
-                "groovy": "g.E().hasLabel(\"trusts\")",
-                "java": "g.E().hasLabel(\"trusts\")",
-                "javascript": "g.E().hasLabel(\"trusts\")",
-                "python": "g.E().has_label('trusts')"
-            }
-        ]
-    },
-    {
-        "scenario": "g_addEXa_b_cX_from_V_to_V_labels_count",
-        "traversals": [
-            {
-                "original": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "language": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "canonical": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "anonymized": "g.addV(string0).property(string1, 
string2).addV(string0).property(string1, string3)",
-                "dotnet": "g.AddV((string) \"person\").Property(\"name\", 
\"marko\").AddV((string) \"person\").Property(\"name\", \"josh\")",
-                "go": "g.AddV(\"person\").Property(\"name\", 
\"marko\").AddV(\"person\").Property(\"name\", \"josh\")",
-                "groovy": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "java": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "javascript": "g.addV(\"person\").property(\"name\", 
\"marko\").addV(\"person\").property(\"name\", \"josh\")",
-                "python": "g.add_v('person').property('name', 
'marko').add_v('person').property('name', 'josh')"
-            },
-            {
-                "original": "g.addE(\"a\", \"b\", 
\"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().count()",
-                "language": "g.addE(\"a\", \"b\", 
\"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().count()",
-                "canonical": "g.addE(\"a\", \"b\", 
\"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().count()",
-                "anonymized": "g.addE(string0, string1, 
string2).from(__.V().has(string3, string4)).to(__.V().has(string3, 
string5)).labels().count()",
-                "dotnet": "g.AddE((string) \"a\", (string) \"b\", (string) 
\"c\").From(__.V().Has(\"name\", \"marko\")).To(__.V().Has(\"name\", 
\"josh\")).Labels().Count()",
-                "go": "g.AddE(\"a\", \"b\", 
\"c\").From(gremlingo.T__.V().Has(\"name\", 
\"marko\")).To(gremlingo.T__.V().Has(\"name\", \"josh\")).Labels().Count()",
-                "groovy": "g.addE(\"a\", \"b\", 
\"c\").from(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().count()",
-                "java": "g.addE(\"a\", \"b\", \"c\").from(__.V().has(\"name\", 
\"marko\")).to(__.V().has(\"name\", \"josh\")).labels().count()",
-                "javascript": "g.addE(\"a\", \"b\", 
\"c\").from_(__.V().has(\"name\", \"marko\")).to(__.V().has(\"name\", 
\"josh\")).labels().count()",
-                "python": "g.add_e('a', 'b', 'c').from_(__.V().has('name', 
'marko')).to(__.V().has('name', 'josh')).labels().count()"
-            }
-        ]
-    },
     {
         "scenario": 
"g_VX1X_addVXanimalX_propertyXage_selectXaX_byXageXX_propertyXname_puppyX",
         "traversals": [
@@ -41652,30 +41570,6 @@
                 "java": "g.E().addLabel(\"friend\").labels().fold()",
                 "javascript": "g.E().addLabel(\"friend\").labels().fold()",
                 "python": "g.E().add_label('friend').labels().fold()"
-            },
-            {
-                "original": "g.E().hasLabel(\"knows\")",
-                "language": "g.E().hasLabel(\"knows\")",
-                "canonical": "g.E().hasLabel(\"knows\")",
-                "anonymized": "g.E().hasLabel(string0)",
-                "dotnet": "g.E().HasLabel(\"knows\")",
-                "go": "g.E().HasLabel(\"knows\")",
-                "groovy": "g.E().hasLabel(\"knows\")",
-                "java": "g.E().hasLabel(\"knows\")",
-                "javascript": "g.E().hasLabel(\"knows\")",
-                "python": "g.E().has_label('knows')"
-            },
-            {
-                "original": "g.E().hasLabel(\"friend\")",
-                "language": "g.E().hasLabel(\"friend\")",
-                "canonical": "g.E().hasLabel(\"friend\")",
-                "anonymized": "g.E().hasLabel(string0)",
-                "dotnet": "g.E().HasLabel(\"friend\")",
-                "go": "g.E().HasLabel(\"friend\")",
-                "groovy": "g.E().hasLabel(\"friend\")",
-                "java": "g.E().hasLabel(\"friend\")",
-                "javascript": "g.E().hasLabel(\"friend\")",
-                "python": "g.E().has_label('friend')"
             }
         ]
     },
@@ -42792,16 +42686,16 @@
         "scenario": "g_E_dropLabelXknowsX_labels",
         "traversals": [
             {
-                "original": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "language": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "canonical": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "anonymized": 
"g.addV(string0).as(string1).addV(string0).as(string2).addE(string3, 
string4).from(string1).to(string2)",
-                "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) 
\"person\").As(\"b\").AddE(\"knows\", \"trusts\").From(\"a\").To(\"b\")",
-                "go": 
"g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\", 
\"trusts\").From(\"a\").To(\"b\")",
-                "groovy": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "java": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "javascript": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from_(\"a\").to(\"b\")",
-                "python": 
"g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 
'trusts').from_('a').to('b')"
+                "original": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "language": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "canonical": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "anonymized": 
"g.addV(string0).as(string1).addV(string0).as(string2).addE(string3).from(string1).to(string2)",
+                "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) 
\"person\").As(\"b\").AddE((string) \"knows\").From(\"a\").To(\"b\")",
+                "go": 
"g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\").From(\"a\").To(\"b\")",
+                "groovy": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "java": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "javascript": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from_(\"a\").to(\"b\")",
+                "python": 
"g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')"
             },
             {
                 "original": "g.E().dropLabel(\"knows\").labels().fold()",
@@ -42814,30 +42708,6 @@
                 "java": "g.E().dropLabel(\"knows\").labels().fold()",
                 "javascript": "g.E().dropLabel(\"knows\").labels().fold()",
                 "python": "g.E().drop_label('knows').labels().fold()"
-            },
-            {
-                "original": "g.E().hasLabel(\"knows\")",
-                "language": "g.E().hasLabel(\"knows\")",
-                "canonical": "g.E().hasLabel(\"knows\")",
-                "anonymized": "g.E().hasLabel(string0)",
-                "dotnet": "g.E().HasLabel(\"knows\")",
-                "go": "g.E().HasLabel(\"knows\")",
-                "groovy": "g.E().hasLabel(\"knows\")",
-                "java": "g.E().hasLabel(\"knows\")",
-                "javascript": "g.E().hasLabel(\"knows\")",
-                "python": "g.E().has_label('knows')"
-            },
-            {
-                "original": "g.E().hasLabel(\"trusts\")",
-                "language": "g.E().hasLabel(\"trusts\")",
-                "canonical": "g.E().hasLabel(\"trusts\")",
-                "anonymized": "g.E().hasLabel(string0)",
-                "dotnet": "g.E().HasLabel(\"trusts\")",
-                "go": "g.E().HasLabel(\"trusts\")",
-                "groovy": "g.E().hasLabel(\"trusts\")",
-                "java": "g.E().hasLabel(\"trusts\")",
-                "javascript": "g.E().hasLabel(\"trusts\")",
-                "python": "g.E().has_label('trusts')"
             }
         ]
     },
@@ -42845,16 +42715,16 @@
         "scenario": "g_E_dropLabels_labels",
         "traversals": [
             {
-                "original": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "language": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "canonical": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "anonymized": 
"g.addV(string0).as(string1).addV(string0).as(string2).addE(string3, 
string4).from(string1).to(string2)",
-                "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) 
\"person\").As(\"b\").AddE(\"knows\", \"trusts\").From(\"a\").To(\"b\")",
-                "go": 
"g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\", 
\"trusts\").From(\"a\").To(\"b\")",
-                "groovy": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "java": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from(\"a\").to(\"b\")",
-                "javascript": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\", 
\"trusts\").from_(\"a\").to(\"b\")",
-                "python": 
"g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows', 
'trusts').from_('a').to('b')"
+                "original": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "language": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "canonical": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "anonymized": 
"g.addV(string0).as(string1).addV(string0).as(string2).addE(string3).from(string1).to(string2)",
+                "dotnet": "g.AddV((string) \"person\").As(\"a\").AddV((string) 
\"person\").As(\"b\").AddE((string) \"knows\").From(\"a\").To(\"b\")",
+                "go": 
"g.AddV(\"person\").As(\"a\").AddV(\"person\").As(\"b\").AddE(\"knows\").From(\"a\").To(\"b\")",
+                "groovy": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "java": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from(\"a\").to(\"b\")",
+                "javascript": 
"g.addV(\"person\").as(\"a\").addV(\"person\").as(\"b\").addE(\"knows\").from_(\"a\").to(\"b\")",
+                "python": 
"g.add_v('person').as_('a').add_v('person').as_('b').add_e('knows').from_('a').to('b')"
             },
             {
                 "original": "g.E().dropLabels().labels()",
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature
index 267cefaec9..70058962bc 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/AddEdge.feature
@@ -529,35 +529,3 @@ Feature: Step - addE()
       """
     When iterated to list
     Then the traversal will raise an error with message containing text of 
"must resolve to a Vertex or the ID of a Vertex present in the graph"
-
-  @MultiLabel
-  Scenario: g_addEXa_bX_from_V_to_V_labels_fold
-    Given the empty graph
-    And the graph initializer of
-      """
-      g.addV("person").property("name", 
"marko").addV("person").property("name", "josh")
-      """
-    And the traversal of
-      """
-      g.addE("knows", "trusts").from(__.V().has("name", 
"marko")).to(__.V().has("name", "josh")).labels().fold()
-      """
-    When iterated to list
-    Then the result should have a count of 1
-    And the graph should return 1 for count of "g.E().hasLabel(\"knows\")"
-    And the graph should return 1 for count of "g.E().hasLabel(\"trusts\")"
-
-  @MultiLabel
-  Scenario: g_addEXa_b_cX_from_V_to_V_labels_count
-    Given the empty graph
-    And the graph initializer of
-      """
-      g.addV("person").property("name", 
"marko").addV("person").property("name", "josh")
-      """
-    And the traversal of
-      """
-      g.addE("a", "b", "c").from(__.V().has("name", 
"marko")).to(__.V().has("name", "josh")).labels().count()
-      """
-    When iterated to list
-    Then the result should be unordered
-      | result |
-      | d[3].l |
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature
index 930e3a181b..af095ecc7a 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/MergeVertex.feature
@@ -1112,5 +1112,5 @@ Feature: Step - mergeV()
     When iterated to list
     Then the result should have a count of 1
     And the graph should return 1 for count of "g.V()"
-    And the graph should return 1 for count of "g.V().hasLabel(\"vertex\")"
+    And the graph should return 0 for count of "g.V().hasLabel(\"vertex\")"
     And the graph should return 0 for count of "g.V().hasLabel(\"person\")"
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature
index 5c0891ebb8..0837669796 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/AddLabel.feature
@@ -77,6 +77,4 @@ Feature: Step - addLabel()
       g.E().addLabel("friend").labels().fold()
       """
     When iterated to list
-    Then the result should have a count of 1
-    And the graph should return 1 for count of "g.E().hasLabel(\"knows\")"
-    And the graph should return 1 for count of "g.E().hasLabel(\"friend\")"
+    Then the traversal will raise an error with message containing text of 
"Cannot add label"
diff --git 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature
 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature
index 0c60f6c3c0..c96e375cde 100644
--- 
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature
+++ 
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/sideEffect/DropLabel.feature
@@ -46,9 +46,7 @@ Feature: Step - dropLabel() / dropLabels()
       g.V().dropLabels().labels()
       """
     When iterated to list
-    Then the result should be unordered
-      | result |
-      | vertex |
+    Then the result should have a count of 0
 
   @MultiLabel
   Scenario: g_V_dropLabelXa_bX_labels
@@ -78,16 +76,14 @@ Feature: Step - dropLabel() / dropLabels()
       g.V().dropLabels().labels()
       """
     When iterated to list
-    Then the result should be unordered
-      | result |
-      | vertex |
+    Then the result should have a count of 0
 
   @MultiLabel
   Scenario: g_E_dropLabelXknowsX_labels
     Given the empty graph
     And the graph initializer of
       """
-      g.addV("person").as("a").addV("person").as("b").addE("knows", 
"trusts").from("a").to("b")
+      
g.addV("person").as("a").addV("person").as("b").addE("knows").from("a").to("b")
       """
     And the traversal of
       """
@@ -95,21 +91,17 @@ Feature: Step - dropLabel() / dropLabels()
       """
     When iterated to list
     Then the result should have a count of 1
-    And the graph should return 0 for count of "g.E().hasLabel(\"knows\")"
-    And the graph should return 1 for count of "g.E().hasLabel(\"trusts\")"
 
   @MultiLabel
   Scenario: g_E_dropLabels_labels
     Given the empty graph
     And the graph initializer of
       """
-      g.addV("person").as("a").addV("person").as("b").addE("knows", 
"trusts").from("a").to("b")
+      
g.addV("person").as("a").addV("person").as("b").addE("knows").from("a").to("b")
       """
     And the traversal of
       """
       g.E().dropLabels().labels()
       """
     When iterated to list
-    Then the result should be unordered
-      | result |
-      | edge   |
+    Then the result should have a count of 0
diff --git 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java
 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java
index c23ccee3e0..fced442b11 100644
--- 
a/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java
+++ 
b/gremlin-util/src/test/java/org/apache/tinkerpop/gremlin/util/ser/binary/TypeSerializerFailureTests.java
@@ -57,7 +57,10 @@ public class TypeSerializerFailureTests {
 
     @Parameterized.Parameters(name = "Value={0}")
     public static Collection input() {
-        final ReferenceVertex vertex = new ReferenceVertex("a vertex", 
(String) null);
+        // Use an unserializable id (raw Object has no registered 
TypeSerializer) to force
+        // serialization failure for vertex/edge cases. Previously null labels 
caused the
+        // failure, but now empty labels are serialized gracefully as empty 
lists.
+        final ReferenceVertex vertex = new ReferenceVertex(new Object(), "a 
vertex");
 
         final BulkSet<Object> bulkSet = new BulkSet<>();
         bulkSet.add(vertex, 1L);
@@ -72,7 +75,7 @@ public class TypeSerializerFailureTests {
                 vertex,
                 bulkSet,
                 Collections.singletonList(vertex),
-                new ReferenceEdge("an edge", (String) null, vertex, vertex),
+                new ReferenceEdge(new Object(), "an edge", vertex, vertex),
                 Lambda.supplier(null),
                 metrics,
                 new DefaultTraversalMetrics(1L, 
Collections.singletonList(metrics)),
diff --git 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java
 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java
index b2b5b99281..3f1f994af9 100644
--- 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java
+++ 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/AbstractTinkerGraph.java
@@ -23,6 +23,7 @@ import 
org.apache.tinkerpop.gremlin.process.computer.GraphComputer;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.LabelCardinality;
 import org.apache.tinkerpop.gremlin.structure.Transaction;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
@@ -63,6 +64,8 @@ public abstract class AbstractTinkerGraph implements Graph {
     public static final String GREMLIN_TINKERGRAPH_GRAPH_FORMAT = 
"gremlin.tinkergraph.graphFormat";
     public static final String GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES 
= "gremlin.tinkergraph.allowNullPropertyValues";
     public static final String GREMLIN_TINKERGRAPH_SERVICE = 
"gremlin.tinkergraph.service";
+    public static final String GREMLIN_TINKERGRAPH_VERTEX_LABEL_CARDINALITY = 
"gremlin.tinkergraph.vertexLabelCardinality";
+    public static final String GREMLIN_TINKERGRAPH_EDGE_LABEL_CARDINALITY = 
"gremlin.tinkergraph.edgeLabelCardinality";
 
     protected AtomicLong currentId = new AtomicLong(-1L);
     protected Map<Object, VertexProperty> vertexProperties = new 
ConcurrentHashMap<>();
@@ -77,6 +80,10 @@ public abstract class AbstractTinkerGraph implements Graph {
     protected IdManager<VertexProperty> vertexPropertyIdManager;
     protected VertexProperty.Cardinality defaultVertexPropertyCardinality;
     protected boolean allowNullPropertyValues;
+    protected LabelCardinality vertexLabelCardinality;
+    protected LabelCardinality edgeLabelCardinality;
+    protected String defaultVertexLabel;
+    protected String defaultEdgeLabel;
 
     protected TinkerServiceRegistry serviceRegistry;
 
@@ -385,6 +392,16 @@ public abstract class AbstractTinkerGraph implements Graph 
{
         public VertexProperty.Cardinality getCardinality(final String key) {
             return defaultVertexPropertyCardinality;
         }
+
+        @Override
+        public LabelCardinality getLabelCardinality() {
+            return vertexLabelCardinality;
+        }
+
+        @Override
+        public String getDefaultLabel() {
+            return defaultVertexLabel;
+        }
     }
 
     public class TinkerGraphEdgeFeatures implements Features.EdgeFeatures {
@@ -406,6 +423,16 @@ public abstract class AbstractTinkerGraph implements Graph 
{
         public boolean willAllowId(final Object id) {
             return edgeIdManager.allow(id);
         }
+
+        @Override
+        public LabelCardinality getLabelCardinality() {
+            return edgeLabelCardinality;
+        }
+
+        @Override
+        public String getDefaultLabel() {
+            return defaultEdgeLabel;
+        }
     }
 
     public class TinkerGraphVertexPropertyFeatures implements 
Features.VertexPropertyFeatures {
diff --git 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java
 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java
index b37913a0aa..c55b3a30ce 100644
--- 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java
+++ 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerEdge.java
@@ -29,6 +29,7 @@ import 
org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -131,12 +132,21 @@ public class TinkerEdge extends TinkerElement implements 
Edge {
 
     @Override
     public Set<String> labels() {
+        if (this.edgeLabels.isEmpty()) {
+            if (!this.graph.edgeLabelCardinality.supportsZeroLabels()) {
+                return Collections.singleton(this.graph.defaultEdgeLabel);
+            }
+            return Collections.emptySet();
+        }
         return Collections.unmodifiableSet(this.edgeLabels);
     }
 
     @Override
     @Deprecated
     public String label() {
+        if (this.edgeLabels.isEmpty()) {
+            return this.graph.edgeLabelCardinality.supportsZeroLabels() ? null 
: this.graph.defaultEdgeLabel;
+        }
         return this.edgeLabels.iterator().next();
     }
 
@@ -147,11 +157,9 @@ public class TinkerEdge extends TinkerElement implements 
Edge {
         for (final String l : labels) {
             ElementHelper.validateLabel(l);
         }
-        // Remove default label if it was the only label
-        if (this.edgeLabels.size() == 1 && 
this.edgeLabels.contains(Edge.DEFAULT_LABEL)) {
-            this.graph.removeEdgeFromAdjacency(this, Edge.DEFAULT_LABEL);
-            this.edgeLabels.remove(Edge.DEFAULT_LABEL);
-        }
+
+        this.graph.edgeLabelCardinality.validateAdd(this.edgeLabels, label, 
labels);
+
         this.edgeLabels.add(label);
         this.graph.addEdgeToAdjacency(this, label);
         for (final String l : labels) {
@@ -164,18 +172,22 @@ public class TinkerEdge extends TinkerElement implements 
Edge {
     @Override
     public void dropLabels() {
         graph.touch(this);
-        for (final String l : new LinkedHashSet<>(this.edgeLabels)) {
+        this.graph.edgeLabelCardinality.validateDropAll(this.edgeLabels);
+
+        for (final String l : new HashSet<>(this.edgeLabels)) {
             this.graph.removeEdgeFromAdjacency(this, l);
         }
         this.edgeLabels.clear();
-        this.edgeLabels.add(Edge.DEFAULT_LABEL);
-        this.graph.addEdgeToAdjacency(this, Edge.DEFAULT_LABEL);
-        this.label = this.edgeLabels.iterator().next();
+        this.label = this.edgeLabels.isEmpty()
+                ? (this.graph.edgeLabelCardinality.supportsZeroLabels() ? null 
: this.graph.defaultEdgeLabel)
+                : this.edgeLabels.iterator().next();
     }
 
     @Override
     public void dropLabel(final String label, final String... labels) {
         graph.touch(this);
+        this.graph.edgeLabelCardinality.validateDrop(this.edgeLabels, label);
+
         if (this.edgeLabels.contains(label)) {
             this.graph.removeEdgeFromAdjacency(this, label);
             this.edgeLabels.remove(label);
@@ -186,11 +198,9 @@ public class TinkerEdge extends TinkerElement implements 
Edge {
                 this.edgeLabels.remove(l);
             }
         }
-        if (this.edgeLabels.isEmpty()) {
-            this.edgeLabels.add(Edge.DEFAULT_LABEL);
-            this.graph.addEdgeToAdjacency(this, Edge.DEFAULT_LABEL);
-        }
-        this.label = this.edgeLabels.iterator().next();
+        this.label = this.edgeLabels.isEmpty()
+                ? (this.graph.edgeLabelCardinality.supportsZeroLabels() ? null 
: this.graph.defaultEdgeLabel)
+                : this.edgeLabels.iterator().next();
     }
 
     @Override
diff --git 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
index b780b71281..b47810dc75 100644
--- 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
+++ 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerGraph.java
@@ -24,6 +24,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.LabelCardinality;
 import org.apache.tinkerpop.gremlin.structure.Transaction;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
@@ -86,6 +87,13 @@ public class TinkerGraph extends AbstractTinkerGraph {
                 
configuration.getString(GREMLIN_TINKERGRAPH_DEFAULT_VERTEX_PROPERTY_CARDINALITY,
 VertexProperty.Cardinality.single.name()));
         allowNullPropertyValues = 
configuration.getBoolean(GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES, false);
 
+        vertexLabelCardinality = LabelCardinality.valueOf(
+                
configuration.getString(GREMLIN_TINKERGRAPH_VERTEX_LABEL_CARDINALITY, 
LabelCardinality.ZERO_OR_MORE.name()));
+        edgeLabelCardinality = LabelCardinality.valueOf(
+                
configuration.getString(GREMLIN_TINKERGRAPH_EDGE_LABEL_CARDINALITY, 
LabelCardinality.ZERO_OR_ONE.name()));
+        defaultVertexLabel = Vertex.DEFAULT_LABEL;
+        defaultEdgeLabel = Edge.DEFAULT_LABEL;
+
         graphLocation = 
configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_LOCATION, null);
         graphFormat = 
configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_FORMAT, null);
 
@@ -136,7 +144,7 @@ public class TinkerGraph extends AbstractTinkerGraph {
         ElementHelper.legalPropertyKeyValueArray(keyValues);
         Object idValue = 
vertexIdManager.convert(ElementHelper.getIdValue(keyValues).orElse(null));
         final Set<String> labels = 
ElementHelper.getLabelsValue(keyValues).orElse(
-                Collections.singleton(Vertex.DEFAULT_LABEL));
+                Collections.singleton(defaultVertexLabel));
 
         if (null != idValue) {
             if (this.vertices.containsKey(idValue))
diff --git 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java
 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java
index ad1c59a511..48bfc7a3de 100644
--- 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java
+++ 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerTransactionGraph.java
@@ -24,6 +24,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategies;
 import org.apache.tinkerpop.gremlin.structure.Edge;
 import org.apache.tinkerpop.gremlin.structure.Element;
 import org.apache.tinkerpop.gremlin.structure.Graph;
+import org.apache.tinkerpop.gremlin.structure.LabelCardinality;
 import org.apache.tinkerpop.gremlin.structure.Transaction;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.apache.tinkerpop.gremlin.structure.VertexProperty;
@@ -85,6 +86,13 @@ public final class TinkerTransactionGraph extends 
AbstractTinkerGraph {
                 
configuration.getString(GREMLIN_TINKERGRAPH_DEFAULT_VERTEX_PROPERTY_CARDINALITY,
 VertexProperty.Cardinality.single.name()));
         allowNullPropertyValues = 
configuration.getBoolean(GREMLIN_TINKERGRAPH_ALLOW_NULL_PROPERTY_VALUES, false);
 
+        vertexLabelCardinality = LabelCardinality.valueOf(
+                
configuration.getString(GREMLIN_TINKERGRAPH_VERTEX_LABEL_CARDINALITY, 
LabelCardinality.ZERO_OR_MORE.name()));
+        edgeLabelCardinality = LabelCardinality.valueOf(
+                
configuration.getString(GREMLIN_TINKERGRAPH_EDGE_LABEL_CARDINALITY, 
LabelCardinality.ZERO_OR_ONE.name()));
+        defaultVertexLabel = Vertex.DEFAULT_LABEL;
+        defaultEdgeLabel = Edge.DEFAULT_LABEL;
+
         graphLocation = 
configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_LOCATION, null);
         graphFormat = 
configuration.getString(GREMLIN_TINKERGRAPH_GRAPH_FORMAT, null);
 
@@ -138,7 +146,7 @@ public final class TinkerTransactionGraph extends 
AbstractTinkerGraph {
         if (null == idValue)
             idValue = vertexIdManager.getNextId(this);
         final Set<String> labels = 
ElementHelper.getLabelsValue(keyValues).orElse(
-                Collections.singleton(Vertex.DEFAULT_LABEL));
+                Collections.singleton(defaultVertexLabel));
 
         this.tx().readWrite();
         final long txNumber = transaction.getTxNumber();
diff --git 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java
 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java
index f3a97beb13..c605841fd0 100644
--- 
a/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java
+++ 
b/tinkergraph-gremlin/src/main/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertex.java
@@ -30,6 +30,7 @@ import 
org.apache.tinkerpop.gremlin.util.iterator.IteratorUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -79,24 +80,41 @@ public class TinkerVertex extends TinkerElement implements 
Vertex {
      * Canonical constructor. Constructs a TinkerVertex with multiple labels 
and a specific version (for transactional graphs).
      */
     protected TinkerVertex(final Object id, final Set<String> labels, final 
AbstractTinkerGraph graph, final long currentVersion) {
-        super(id, (labels == null || labels.isEmpty()) ? Vertex.DEFAULT_LABEL 
: labels.iterator().next(), currentVersion);
+        super(id, null, currentVersion);  // label field set below
         this.graph = graph;
         this.isTxMode = graph instanceof TinkerTransactionGraph;
         this.allowNullPropertyValues = 
graph.features().vertex().supportsNullPropertyValues();
-        this.vertexLabels = (labels == null || labels.isEmpty())
-                ? new 
LinkedHashSet<>(Collections.singleton(Vertex.DEFAULT_LABEL))
-                : new LinkedHashSet<>(labels);
+        // Store only explicit labels — never store the default label 
physically
+        this.vertexLabels = (labels == null) ? new HashSet<>() : new 
HashSet<>(labels);
+        // Set the cached label field to the effective value (including 
virtual default)
+        this.label = effectiveLabel();
+    }
+
+    /**
+     * Computes the effective single label for the deprecated label() API and 
the cached field.
+     */
+    private String effectiveLabel() {
+        if (this.vertexLabels.isEmpty()) {
+            return this.graph.vertexLabelCardinality.supportsZeroLabels() ? 
null : this.graph.defaultVertexLabel;
+        }
+        return this.vertexLabels.iterator().next();
     }
 
     @Override
     public Set<String> labels() {
+        if (this.vertexLabels.isEmpty()) {
+            if (!this.graph.vertexLabelCardinality.supportsZeroLabels()) {
+                return Collections.singleton(this.graph.defaultVertexLabel);
+            }
+            return Collections.emptySet();
+        }
         return Collections.unmodifiableSet(this.vertexLabels);
     }
 
     @Override
     @Deprecated
     public String label() {
-        return this.vertexLabels.iterator().next();
+        return effectiveLabel();
     }
 
     @Override
@@ -106,36 +124,33 @@ public class TinkerVertex extends TinkerElement 
implements Vertex {
             ElementHelper.validateLabel(l);
         }
 
-        // Remove default label if it was the only label and we're adding real 
labels
-        if (this.vertexLabels.size() == 1 && 
this.vertexLabels.contains(Vertex.DEFAULT_LABEL)) {
-            this.vertexLabels.remove(Vertex.DEFAULT_LABEL);
-        }
+        this.graph.vertexLabelCardinality.validateAdd(this.vertexLabels, 
label, labels);
 
         this.vertexLabels.add(label);
         Collections.addAll(this.vertexLabels, labels);
-        this.label = this.vertexLabels.iterator().next();
+        this.label = effectiveLabel();
         this.graph.updateVertexLabelIndex(this);
     }
 
     @Override
     public void dropLabels() {
+        this.graph.vertexLabelCardinality.validateDropAll(this.vertexLabels);
+
         this.vertexLabels.clear();
-        this.vertexLabels.add(Vertex.DEFAULT_LABEL);
-        this.label = this.vertexLabels.iterator().next();
+        this.label = effectiveLabel();
         this.graph.updateVertexLabelIndex(this);
     }
 
     @Override
     public void dropLabel(final String label, final String... labels) {
+        this.graph.vertexLabelCardinality.validateDrop(this.vertexLabels, 
label);
+
         this.vertexLabels.remove(label);
         for (final String l : labels) {
             this.vertexLabels.remove(l);
         }
 
-        if (this.vertexLabels.isEmpty()) {
-            this.vertexLabels.add(Vertex.DEFAULT_LABEL);
-        }
-        this.label = this.vertexLabels.iterator().next();
+        this.label = effectiveLabel();
         this.graph.updateVertexLabelIndex(this);
     }
 
@@ -267,6 +282,24 @@ public class TinkerVertex extends TinkerElement implements 
Vertex {
         final List<Edge> edges = new ArrayList<>();
         this.edges(Direction.BOTH).forEachRemaining(edge -> edges.add(edge));
         edges.stream().filter(edge -> !((TinkerEdge) 
edge).removed).forEach(Edge::remove);
+
+        // Also remove any orphaned edges from the global edges map that 
reference this vertex.
+        // Edges can become orphaned from the adjacency maps when their labels 
are dropped via
+        // dropLabels()/dropLabel(), which removes them from the vertex's 
outEdges/inEdges but
+        // leaves them in the graph's global edges map.
+        final Object thisId = this.id();
+        final List<Object> orphanedEdgeIds = new ArrayList<>();
+        graph.edges().forEachRemaining(edge -> {
+            if (!((TinkerEdge) edge).removed) {
+                if (edge.outVertex().id().equals(thisId) || 
edge.inVertex().id().equals(thisId)) {
+                    orphanedEdgeIds.add(edge.id());
+                }
+            }
+        });
+        for (final Object edgeId : orphanedEdgeIds) {
+            graph.removeEdge(edgeId);
+        }
+
         TinkerIndexHelper.removeElementIndex(this);
         if (null != this.properties)
             this.properties.values().forEach(vpList -> vpList.forEach(vp -> 
graph.vertexProperties.remove(vp.id())));
diff --git 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java
 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java
index 2257a15b60..d1f39a8265 100644
--- 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java
+++ 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/map/MergeVMultiLabelTest.java
@@ -147,8 +147,7 @@ public class MergeVMultiLabelTest {
         g.mergeV(Map.of(T.label, "person", "name", "marko"))
                 .option(Merge.onMatch, Map.of(T.label, 
Collections.emptySet())).next();
 
-        // empty collection triggers default label behavior
-        assertThat(v.labels(), hasSize(1));
-        assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL));
+        // Under ZERO_OR_MORE cardinality, empty collection means no labels
+        assertThat(v.labels(), hasSize(0));
     }
 }
diff --git 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java
 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java
index 5aeea9daa8..71ffc0ce94 100644
--- 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java
+++ 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationPropertyTest.java
@@ -133,10 +133,9 @@ public class LabelMutationPropertyTest {
             // drop all labels
             g.V(v).dropLabels().iterate();
 
-            assertThat("Iteration " + i + ": after dropLabels(), vertex should 
have exactly one label",
-                    v.labels(), hasSize(1));
-            assertThat("Iteration " + i + ": after dropLabels(), vertex should 
have default label",
-                    v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL));
+            // Under ZERO_OR_MORE cardinality, dropping all labels results in 
empty set
+            assertThat("Iteration " + i + ": after dropLabels(), vertex should 
have no labels",
+                    v.labels(), hasSize(0));
         }
     }
 
diff --git 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java
 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java
index 7ac5c88015..d9c00fbfc6 100644
--- 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java
+++ 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/step/sideEffect/LabelMutationStepTest.java
@@ -78,14 +78,13 @@ public class LabelMutationStepTest {
         assertThat(v.labels(), containsInAnyOrder("person", "manager"));
     }
 
-    @Test
+    @Test(expected = IllegalStateException.class)
     public void shouldAddLabelToEdgeViaTraversal() {
         final Vertex v1 = g.addV("person").next();
         final Vertex v2 = g.addV("person").next();
         final Edge e = v1.addEdge("knows", v2);
+        // Under ZERO_OR_ONE cardinality for edges, adding a second label 
throws
         g.E().addLabel("friend").iterate();
-        assertThat(e.labels(), hasSize(2));
-        assertThat(e.labels(), containsInAnyOrder("knows", "friend"));
     }
 
     // --- dropLabel step tests ---
@@ -102,8 +101,8 @@ public class LabelMutationStepTest {
     public void shouldDropAllLabelsViaTraversal() {
         final Vertex v = g.addV("person").addLabel("employee").next();
         g.V(v).dropLabels().iterate();
-        assertThat(v.labels(), hasSize(1));
-        assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL));
+        // Under ZERO_OR_MORE cardinality, dropping all labels results in 
empty set
+        assertThat(v.labels(), hasSize(0));
     }
 
     @Test
@@ -120,8 +119,8 @@ public class LabelMutationStepTest {
         final Vertex v2 = g.addV("person").next();
         final Edge e = v1.addEdge("knows", v2);
         g.E().dropLabels().iterate();
-        assertThat(e.labels(), hasSize(1));
-        assertThat(e.labels(), containsInAnyOrder(Edge.DEFAULT_LABEL));
+        // Under ZERO_OR_ONE cardinality with supportsZeroLabels, edge labels 
become empty
+        assertThat(e.labels(), hasSize(0));
     }
 
     // --- addV multi-label tests ---
diff --git 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java
 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java
index 27387d60e9..ffd5efb697 100644
--- 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java
+++ 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/structure/TinkerVertexMultiLabelTest.java
@@ -119,8 +119,8 @@ public class TinkerVertexMultiLabelTest {
     public void shouldDropAllLabelsAndAssignDefault() {
         final Vertex v = g.addV("person").addLabel("employee").next();
         v.dropLabels();
-        assertThat(v.labels(), hasSize(1));
-        assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL));
+        // Under ZERO_OR_MORE cardinality, dropping all labels results in 
empty set (no virtual default)
+        assertThat(v.labels(), hasSize(0));
     }
 
     @Test
@@ -143,18 +143,17 @@ public class TinkerVertexMultiLabelTest {
     public void shouldAssignDefaultWhenDroppingLastSpecificLabel() {
         final Vertex v = g.addV("person").next();
         v.dropLabel("person");
-        assertThat(v.labels(), hasSize(1));
-        assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL));
+        // Under ZERO_OR_MORE cardinality, dropping last label results in 
empty set (no virtual default)
+        assertThat(v.labels(), hasSize(0));
     }
 
-    @Test
+    @Test(expected = IllegalStateException.class)
     public void shouldAddLabelToEdge() {
         final Vertex v1 = g.addV("person").next();
         final Vertex v2 = g.addV("person").next();
         final Edge e = v1.addEdge("knows", v2);
+        // Under ZERO_OR_ONE cardinality for edges, adding a second label 
throws
         e.addLabel("friend");
-        assertThat(e.labels(), hasSize(2));
-        assertThat(e.labels(), containsInAnyOrder("knows", "friend"));
     }
 
     @Test
@@ -163,8 +162,8 @@ public class TinkerVertexMultiLabelTest {
         final Vertex v2 = g.addV("person").next();
         final Edge e = v1.addEdge("knows", v2);
         e.dropLabels();
-        assertThat(e.labels(), hasSize(1));
-        assertThat(e.labels(), containsInAnyOrder(Edge.DEFAULT_LABEL));
+        // Under ZERO_OR_ONE cardinality for edges with supportsZeroLabels, 
labels() returns empty set
+        assertThat(e.labels(), hasSize(0));
     }
 
     @Test
@@ -177,12 +176,13 @@ public class TinkerVertexMultiLabelTest {
     }
 
     @Test
-    public void shouldRemoveDefaultLabelWhenAddingFirstRealLabel() {
+    public void shouldAddLabelToExistingVertexWithDefaultLabel() {
+        // Under ZERO_OR_MORE, addV() assigns "vertex" physically. Adding 
"person" simply adds to the set.
         final Vertex v = g.addV().next();
         assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL));
         v.addLabel("person");
-        assertThat(v.labels(), hasSize(1));
-        assertThat(v.labels(), containsInAnyOrder("person"));
+        assertThat(v.labels(), hasSize(2));
+        assertThat(v.labels(), containsInAnyOrder(Vertex.DEFAULT_LABEL, 
"person"));
     }
 
     @Test

Reply via email to