diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigNodeComplexValue.java b/config/src/main/java/com/typesafe/config/impl/ConfigNodeComplexValue.java
index 1523e759..56885fe7 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigNodeComplexValue.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigNodeComplexValue.java
@@ -33,7 +33,7 @@ final class ConfigNodeComplexValue extends AbstractConfigNodeValue {
                 continue;
             }
             node = (ConfigNodeKeyValue)children.get(i);
-            key = Path.newPath(node.key().render());
+            key = node.key().value();
             if (key.equals(desiredPath)) {
                 if (!replaced) {
                     childrenCopy.set(i, node.replaceValue(value));
@@ -67,7 +67,7 @@ final class ConfigNodeComplexValue extends AbstractConfigNodeValue {
             ArrayList<AbstractConfigNode> childrenCopy = new ArrayList<AbstractConfigNode>(children);
             ArrayList<AbstractConfigNode> newNodes = new ArrayList();
             newNodes.add(new ConfigNodeSingleToken(Tokens.newLine(null)));
-            newNodes.add(new ConfigNodeKey(Tokens.newUnquotedText(null, desiredPath.render())));
+            newNodes.add(new ConfigNodeKey(desiredPath));
             newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
             newNodes.add(new ConfigNodeSingleToken(Tokens.COLON));
             newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
diff --git a/config/src/main/java/com/typesafe/config/impl/ConfigNodeKey.java b/config/src/main/java/com/typesafe/config/impl/ConfigNodeKey.java
index 0dd76eba..7e157847 100644
--- a/config/src/main/java/com/typesafe/config/impl/ConfigNodeKey.java
+++ b/config/src/main/java/com/typesafe/config/impl/ConfigNodeKey.java
@@ -1,15 +1,18 @@
 package com.typesafe.config.impl;
 
 import java.util.Collection;
-import java.util.Collections;
 
 final class ConfigNodeKey extends AbstractConfigNode {
-    Token token;
-    ConfigNodeKey(Token t) {
-        token = t;
+    final private Path key;
+    ConfigNodeKey(Path key) {
+        this.key = key;
     }
 
     protected Collection<Token> tokens() {
-        return Collections.singletonList(token);
+        return key.tokens();
+    }
+
+    protected Path value() {
+        return key;
     }
 }
diff --git a/config/src/main/java/com/typesafe/config/impl/Parser.java b/config/src/main/java/com/typesafe/config/impl/Parser.java
index 6287c063..e5b9362f 100644
--- a/config/src/main/java/com/typesafe/config/impl/Parser.java
+++ b/config/src/main/java/com/typesafe/config/impl/Parser.java
@@ -1063,6 +1063,7 @@ final class Parser {
     private static Path parsePathExpression(Iterator<Token> expression,
             ConfigOrigin origin, String originalText) {
         // each builder in "buf" is an element in the path.
+        ArrayList<Token> pathTokens = new ArrayList<Token>();
         List<Element> buf = new ArrayList<Element>();
         buf.add(new Element("", false));
 
@@ -1073,6 +1074,7 @@ final class Parser {
 
         while (expression.hasNext()) {
             Token t = expression.next();
+            pathTokens.add(t);
 
             // Ignore all IgnoredWhitespace tokens
             if (Tokens.isIgnoredWhitespace(t))
@@ -1119,7 +1121,7 @@ final class Parser {
             }
         }
 
-        PathBuilder pb = new PathBuilder();
+        PathBuilder pb = new PathBuilder(pathTokens);
         for (Element e : buf) {
             if (e.sb.length() == 0 && !e.canBeEmpty) {
                 throw new ConfigException.BadPath(
@@ -1192,8 +1194,10 @@ final class Parser {
     private static Path fastPathBuild(Path tail, String s, int end) {
         // lastIndexOf takes last index it should look at, end - 1 not end
         int splitAt = s.lastIndexOf('.', end - 1);
+        ArrayList<Token> tokens = new ArrayList<Token>();
+        tokens.add(Tokens.newUnquotedText(null, s));
         // this works even if splitAt is -1; then we start the substring at 0
-        Path withOneMoreElement = new Path(s.substring(splitAt + 1, end), tail);
+        Path withOneMoreElement = new Path(s.substring(splitAt + 1, end), tail, tokens);
         if (splitAt < 0) {
             return withOneMoreElement;
         } else {
diff --git a/config/src/main/java/com/typesafe/config/impl/Path.java b/config/src/main/java/com/typesafe/config/impl/Path.java
index 51e5b788..5cb041a1 100644
--- a/config/src/main/java/com/typesafe/config/impl/Path.java
+++ b/config/src/main/java/com/typesafe/config/impl/Path.java
@@ -3,6 +3,8 @@
  */
 package com.typesafe.config.impl;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 
@@ -13,12 +15,22 @@ final class Path {
     final private String first;
     final private Path remainder;
 
+    // We only need to keep track of this for top-level paths created with
+    // parsePath, so this will be empty or null for all other cases
+    final private ArrayList<Token> tokens;
+
     Path(String first, Path remainder) {
+        this(first, remainder, new ArrayList<Token>());
+    }
+
+    Path(String first, Path remainder, Collection<Token> tokens) {
         this.first = first;
         this.remainder = remainder;
+        this.tokens = new ArrayList<Token>(tokens);
     }
 
     Path(String... elements) {
+        this.tokens = null;
         if (elements.length == 0)
             throw new ConfigException.BugOrBroken("empty path");
         this.first = elements[0];
@@ -40,6 +52,7 @@ final class Path {
 
     // append all the paths in the iterator together into one path
     Path(Iterator<Path> i) {
+        this.tokens = null;
         if (!i.hasNext())
             throw new ConfigException.BugOrBroken("empty path");
 
@@ -204,6 +217,10 @@ final class Path {
         }
     }
 
+    protected Collection<Token> tokens() {
+        return tokens;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
diff --git a/config/src/main/java/com/typesafe/config/impl/PathBuilder.java b/config/src/main/java/com/typesafe/config/impl/PathBuilder.java
index ede6c663..bd6b162e 100644
--- a/config/src/main/java/com/typesafe/config/impl/PathBuilder.java
+++ b/config/src/main/java/com/typesafe/config/impl/PathBuilder.java
@@ -3,6 +3,8 @@
  */
 package com.typesafe.config.impl;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Stack;
 
 import com.typesafe.config.ConfigException;
@@ -12,8 +14,17 @@ final class PathBuilder {
     final private Stack<String> keys;
     private Path result;
 
+    // the tokens only matter for top-level paths created with parsePath, in all
+    // other cases this will be empty
+    final private ArrayList<Token> tokens;
+
     PathBuilder() {
+        this(new ArrayList<Token>());
+    }
+
+    PathBuilder(Collection<Token> tokens) {
         keys = new Stack<String>();
+        this.tokens = new ArrayList<Token>(tokens);
     }
 
     private void checkCanAppend() {
@@ -51,7 +62,7 @@ final class PathBuilder {
             Path remainder = null;
             while (!keys.isEmpty()) {
                 String key = keys.pop();
-                remainder = new Path(key, remainder);
+                remainder = new Path(key, remainder, tokens);
             }
             result = remainder;
         }
diff --git a/config/src/test/scala/com/typesafe/config/impl/ConfigNodeTest.scala b/config/src/test/scala/com/typesafe/config/impl/ConfigNodeTest.scala
index fc245091..f57ec3f7 100644
--- a/config/src/test/scala/com/typesafe/config/impl/ConfigNodeTest.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/ConfigNodeTest.scala
@@ -11,9 +11,9 @@ class ConfigNodeTest extends TestUtils {
         assertEquals(node.render(), token.tokenText())
     }
 
-    private def keyNodeTest(token: Token) {
-        val node = configNodeKey(token)
-        assertEquals(node.render(), token.tokenText())
+    private def keyNodeTest(path: String) {
+        val node = configNodeKey(path)
+        assertEquals(path, node.render())
     }
 
     private def simpleValueNodeTest(token: Token) {
@@ -32,21 +32,21 @@ class ConfigNodeTest extends TestUtils {
         assertEquals(newValue.render(), newKeyValNode.value().render())
     }
 
-    private def topLevelValueReplaceTest(value: AbstractConfigNodeValue, newValue: AbstractConfigNodeValue, key: Token = tokenString("foo")) {
+    private def topLevelValueReplaceTest(value: AbstractConfigNodeValue, newValue: AbstractConfigNodeValue, key: String = "foo") {
         val complexNodeChildren = List(nodeOpenBrace,
                                        nodeKeyValuePair(nodeWhitespace("       "), configNodeKey(key),value, nodeWhitespace("    ")),
                                        nodeCloseBrace)
         val complexNode = configNodeComplexValue(complexNodeChildren)
-        val newNode = complexNode.setValueOnPath(Path.newPath(key.tokenText()), newValue)
-        val origText = "{       " + key.tokenText() + " : " + value.render() + "    }"
-        val finalText = "{       " + key.tokenText() + " : " + newValue.render() + "    }"
+        val newNode = complexNode.setValueOnPath(Path.newPath(key), newValue)
+        val origText = "{       " + key + " : " + value.render() + "    }"
+        val finalText = "{       " + key + " : " + newValue.render() + "    }"
 
         assertEquals(origText, complexNode.render())
         assertEquals(finalText, newNode.render())
     }
 
     private def replaceDuplicatesTest(value1: AbstractConfigNodeValue, value2: AbstractConfigNodeValue, value3: AbstractConfigNodeValue) {
-        val key = nodeUnquotedKey("foo")
+        val key = configNodeKey("foo")
         val keyValPair1 = nodeKeyValuePair(key, value1)
         val keyValPair2 = nodeKeyValuePair(key, value2)
         val keyValPair3 = nodeKeyValuePair(key, value3)
@@ -59,7 +59,7 @@ class ConfigNodeTest extends TestUtils {
     }
 
     private def nonExistentPathTest(value: AbstractConfigNodeValue) {
-        val node = configNodeComplexValue(List(nodeKeyValuePair(nodeUnquotedKey("bar"), nodeInt(15))))
+        val node = configNodeComplexValue(List(nodeKeyValuePair(configNodeKey("bar"), nodeInt(15))))
         assertEquals("bar : 15", node.render())
         val newNode = node.setValueOnPath(Path.newPath("foo"), value)
         val finalText = "bar : 15\nfoo : " + value.render() + "\n"
@@ -89,8 +89,8 @@ class ConfigNodeTest extends TestUtils {
     @Test
     def createConfigNodeSetting() {
         //Ensure a ConfigNodeSetting can handle the normal key types
-        keyNodeTest(tokenUnquoted("foo"))
-        keyNodeTest(tokenString("Hello I am a key how are you today"))
+        keyNodeTest("foo")
+        keyNodeTest("\"Hello I am a key how are you today\"")
     }
 
     @Test
@@ -112,12 +112,12 @@ class ConfigNodeTest extends TestUtils {
     @Test
     def createConfigNodeKeyValue() {
         // Supports Quoted and Unquoted keys
-        keyValueNodeTest(nodeQuotedKey("abc"), nodeInt(123), nodeLine(1), nodeInt(245))
-        keyValueNodeTest(nodeUnquotedKey("abc"), nodeInt(123), nodeLine(1), nodeInt(245))
+        keyValueNodeTest(configNodeKey("\"abc\""), nodeInt(123), nodeLine(1), nodeInt(245))
+        keyValueNodeTest(configNodeKey("abc"), nodeInt(123), nodeLine(1), nodeInt(245))
 
         // Can replace value with values of different types
-        keyValueNodeTest(nodeQuotedKey("abc"), nodeInt(123), nodeLine(1), nodeString("I am a string"))
-        keyValueNodeTest(nodeQuotedKey("abc"), nodeInt(123), nodeLine(1), configNodeComplexValue(List(nodeOpenBrace, nodeCloseBrace)))
+        keyValueNodeTest(configNodeKey("\"abc\""), nodeInt(123), nodeLine(1), nodeString("I am a string"))
+        keyValueNodeTest(configNodeKey("\"abc\""), nodeInt(123), nodeLine(1), configNodeComplexValue(List(nodeOpenBrace, nodeCloseBrace)))
     }
 
     @Test
@@ -142,7 +142,7 @@ class ConfigNodeTest extends TestUtils {
         topLevelValueReplaceTest(array, configNodeComplexValue(List(nodeOpenBrace, nodeCloseBrace)))
 
         //Ensure maps can be replaced
-        val nestedMap = configNodeComplexValue(List(nodeOpenBrace, nodeUnquotedKey("abc"),
+        val nestedMap = configNodeComplexValue(List(nodeOpenBrace, configNodeKey("abc"),
                                                     nodeColon, configNodeSimpleValue(tokenString("a string")),
                                                     nodeCloseBrace))
         topLevelValueReplaceTest(nestedMap, nodeInt(10))
@@ -152,7 +152,7 @@ class ConfigNodeTest extends TestUtils {
         topLevelValueReplaceTest(nestedMap, configNodeComplexValue(List(nodeOpenBrace, nodeCloseBrace)))
 
         //Ensure a key with format "a.b" will be properly replaced
-        topLevelValueReplaceTest(nodeInt(10), nestedMap, tokenUnquoted("foo.bar"))
+        topLevelValueReplaceTest(nodeInt(10), nestedMap, "foo.bar")
     }
 
     @Test
@@ -170,7 +170,7 @@ class ConfigNodeTest extends TestUtils {
     def addNonExistentPaths() {
         nonExistentPathTest(nodeInt(10))
         nonExistentPathTest(configNodeComplexValue(List(nodeOpenBracket, nodeInt(15), nodeCloseBracket)))
-        nonExistentPathTest(configNodeComplexValue(List(nodeOpenBrace, nodeKeyValuePair(nodeUnquotedKey("foo"), nodeDouble(3.14), nodeSpace))))
+        nonExistentPathTest(configNodeComplexValue(List(nodeOpenBrace, nodeKeyValuePair(configNodeKey("foo"), nodeDouble(3.14), nodeSpace))))
     }
 
     @Test
@@ -179,23 +179,23 @@ class ConfigNodeTest extends TestUtils {
         val origText = "foo : bar\nbaz : {\n\t\"abc.def\" : 123\n\t//This is a comment about the below setting\n\n\tabc : {\n\t\t" +
           "def : \"this is a string\"\n\t\tghi : ${\"a.b\"}\n\t}\n}\nbaz.abc.ghi : 52\nbaz.abc.ghi : 53\n}"
         val lowestLevelMap = configNodeComplexValue(List(nodeOpenBrace, nodeLine(6),
-                                                         nodeKeyValuePair(nodeWhitespace("\t\t"), nodeUnquotedKey("def"), configNodeSimpleValue(tokenString("this is a string")), nodeLine(7)),
-                                                         nodeKeyValuePair(nodeWhitespace("\t\t"), nodeUnquotedKey("ghi"), configNodeSimpleValue(tokenKeySubstitution("a.b")), nodeLine(8)),
+                                                         nodeKeyValuePair(nodeWhitespace("\t\t"), configNodeKey("def"), configNodeSimpleValue(tokenString("this is a string")), nodeLine(7)),
+                                                         nodeKeyValuePair(nodeWhitespace("\t\t"), configNodeKey("ghi"), configNodeSimpleValue(tokenKeySubstitution("a.b")), nodeLine(8)),
                                                          nodeWhitespace("\t"), nodeCloseBrace))
         val higherLevelMap = configNodeComplexValue(List(nodeOpenBrace, nodeLine(2),
-                                                         nodeKeyValuePair(nodeWhitespace("\t"), configNodeKey(tokenString("abc.def")), configNodeSimpleValue(tokenInt(123)), nodeLine(3)),
+                                                         nodeKeyValuePair(nodeWhitespace("\t"), configNodeKey("\"abc.def\""), configNodeSimpleValue(tokenInt(123)), nodeLine(3)),
                                                          nodeWhitespace("\t"), configNodeBasic(tokenCommentDoubleSlash("This is a comment about the below setting")),
                                                          nodeLine(4), nodeLine(5),
-                                                         nodeKeyValuePair(nodeWhitespace("\t"), nodeUnquotedKey("abc"), lowestLevelMap, nodeLine(9)), nodeWhitespace(""),
+                                                         nodeKeyValuePair(nodeWhitespace("\t"), configNodeKey("abc"), lowestLevelMap, nodeLine(9)), nodeWhitespace(""),
                                                          nodeCloseBrace))
-        val origNode =  configNodeComplexValue(List(nodeKeyValuePair(nodeUnquotedKey("foo"), configNodeSimpleValue(tokenUnquoted("bar")), nodeLine(1)),
-                                                    nodeKeyValuePair(nodeUnquotedKey("baz"), higherLevelMap, nodeLine(10)),
-                                                    nodeKeyValuePair(nodeUnquotedKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(52)), nodeLine(11)),
-                                                    nodeKeyValuePair(nodeUnquotedKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(53)), nodeLine(12)),
+        val origNode =  configNodeComplexValue(List(nodeKeyValuePair(configNodeKey("foo"), configNodeSimpleValue(tokenUnquoted("bar")), nodeLine(1)),
+                                                    nodeKeyValuePair(configNodeKey("baz"), higherLevelMap, nodeLine(10)),
+                                                    nodeKeyValuePair(configNodeKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(52)), nodeLine(11)),
+                                                    nodeKeyValuePair(configNodeKey("baz.abc.ghi"), configNodeSimpleValue(tokenInt(53)), nodeLine(12)),
                                                     nodeCloseBrace))
         assertEquals(origText, origNode.render())
         val finalText = "foo : bar\nbaz : {\n\t\"abc.def\" : true\n\t//This is a comment about the below setting\n\n\tabc : {\n\t\t" +
-          "def : false\n\t}\n}\nbaz.abc.ghi : randomunquotedString\n}\nbaz.abc.this.does.not.exist : doesnotexist\n"
+          "def : false\n\t}\n}\nbaz.abc.ghi : randomunquotedString\n}\nbaz.abc.\"this.does.not.exist@@@+$#\".end : doesnotexist\n"
 
         //Can replace settings in nested maps
         // Paths with quotes in the name are treated as a single Path, rather than multiple sub-paths
@@ -206,7 +206,7 @@ class ConfigNodeTest extends TestUtils {
         newNode = newNode.setValueOnPath(Path.newPath("baz.abc.ghi"), configNodeSimpleValue(tokenUnquoted("randomunquotedString")))
 
         // Missing paths are added to the top level if they don't appear anywhere, including in nested maps
-        newNode = newNode.setValueOnPath(Path.newPath("baz.abc.this.does.not.exist"), configNodeSimpleValue(tokenUnquoted("doesnotexist")))
+        newNode = newNode.setValueOnPath(Path.newPath("baz.abc.\"this.does.not.exist@@@+$#\".end"), configNodeSimpleValue(tokenUnquoted("doesnotexist")))
 
         // The above operations cause the resultant map to be rendered properly
         assertEquals(finalText, newNode.render())
diff --git a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
index 50ede888..3d7cfcb4 100644
--- a/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
+++ b/config/src/test/scala/com/typesafe/config/impl/TestUtils.scala
@@ -667,8 +667,9 @@ abstract trait TestUtils {
         new ConfigNodeSimpleValue(value)
     }
 
-    def configNodeKey(value: Token) = {
-        new ConfigNodeKey(value)
+    def configNodeKey(path: String) = {
+        val parsedPath = Parser.parsePath(path)
+        new ConfigNodeKey(parsedPath)
     }
 
     def configNodeBasic(value: Token) = {
@@ -688,8 +689,6 @@ abstract trait TestUtils {
     def nodeComma = new ConfigNodeSingleToken(Tokens.COMMA)
     def nodeLine(line: Integer) = new ConfigNodeSingleToken(tokenLine(line))
     def nodeWhitespace(whitespace: String) = new ConfigNodeSingleToken(tokenWhitespace(whitespace))
-    def nodeQuotedKey(key: String) = configNodeKey(tokenString(key))
-    def nodeUnquotedKey(key: String) = configNodeKey(tokenUnquoted(key))
     def nodeKeyValuePair(key: ConfigNodeKey, value: AbstractConfigNodeValue) = {
         val nodes = List(key, nodeSpace, nodeColon, nodeSpace, value)
         new ConfigNodeKeyValue(nodes.asJavaCollection)