diff --git a/src/main/java/com/typesafe/config/impl/Parser.java b/src/main/java/com/typesafe/config/impl/Parser.java
index d0c14c6e..2248880d 100644
--- a/src/main/java/com/typesafe/config/impl/Parser.java
+++ b/src/main/java/com/typesafe/config/impl/Parser.java
@@ -326,6 +326,51 @@ final class Parser {
             }
         }
 
+        private static boolean isIncludeKeyword(Token t) {
+            return Tokens.isUnquotedText(t)
+                    && Tokens.getUnquotedText(t).equals("include");
+        }
+
+        private static boolean isUnquotedWhitespace(Token t) {
+            if (!Tokens.isUnquotedText(t))
+                return false;
+
+            String s = Tokens.getUnquotedText(t);
+
+            for (int i = 0; i < s.length(); ++i) {
+                char c = s.charAt(i);
+                if (!Character.isWhitespace(c))
+                    return false;
+            }
+            return true;
+        }
+
+        private void parseInclude(Map<String, AbstractConfigValue> values) {
+            Token t = nextTokenIgnoringNewline();
+            while (isUnquotedWhitespace(t)) {
+                t = nextTokenIgnoringNewline();
+            }
+
+            if (Tokens.isValueWithType(t, ConfigValueType.STRING)) {
+                String name = (String) Tokens.getValue(t).unwrapped();
+                AbstractConfigObject obj = includer.include(name);
+
+                for (String key : obj.keySet()) {
+                    AbstractConfigValue v = obj.get(key);
+                    AbstractConfigValue existing = values.get(key);
+                    if (existing != null) {
+                        values.put(key, v.withFallback(existing));
+                    } else {
+                        values.put(key, v);
+                    }
+                }
+
+            } else {
+                throw parseError("include keyword is not followed by a quoted string, but by: "
+                        + t);
+            }
+        }
+
         private AbstractConfigObject parseObject() {
             // invoked just after the OPEN_CURLY
             Map<String, AbstractConfigValue> values = new HashMap<String, AbstractConfigValue>();
@@ -338,6 +383,10 @@ final class Parser {
                         throw parseError("expecting a field name after comma, got a close brace }");
                     }
                     break;
+                } else if (flavor != SyntaxFlavor.JSON && isIncludeKeyword(t)) {
+                    parseInclude(values);
+
+                    afterComma = false;
                 } else {
                     Path path = parseKey(t);
                     Token afterKey = nextTokenIgnoringNewline();
diff --git a/src/test/resources/test03.conf b/src/test/resources/test03.conf
new file mode 100644
index 00000000..54cafe30
--- /dev/null
+++ b/src/test/resources/test03.conf
@@ -0,0 +1,17 @@
+{
+    "test01" : {
+        "ints" : 12,
+        include "test01",
+        "booleans" : 42
+    },
+
+    "test02" : {
+        include   
+
+   "test02.conf"
+    },
+
+    "equiv01" : {
+        include "equiv01/original.json"
+    }
+}
diff --git a/src/test/scala/com/typesafe/config/impl/ConfigTest.scala b/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
index f66cd3b9..7b742c84 100644
--- a/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
+++ b/src/test/scala/com/typesafe/config/impl/ConfigTest.scala
@@ -634,4 +634,22 @@ class ConfigTest extends TestUtils {
         assertEquals(57, conf.getInt(""" "a"."b"."c" """))
         assertEquals(103, conf.getInt(""" "a.b.c" """))
     }
+
+    @Test
+    def test03Includes() {
+        val conf = Config.load("test03")
+
+        // include should have overridden the "ints" value in test03
+        assertEquals(42, conf.getInt("test01.ints.fortyTwo"))
+        // include should have been overridden by 42
+        assertEquals(42, conf.getInt("test01.booleans"));
+        assertEquals(42, conf.getInt("test01.booleans"));
+        // include should have gotten .properties and .json also
+        assertEquals("abc", conf.getString("test01.fromProps.abc"))
+        assertEquals("A", conf.getString("test01.fromJsonA"))
+        // test02 was included
+        assertEquals(57, conf.getInt("test02.a.b.c"))
+        // equiv01/original.json was included (it has a slash in the name)
+        assertEquals("a", conf.getString("equiv01.strings.a"))
+    }
 }
diff --git a/src/test/scala/com/typesafe/config/impl/TestUtils.scala b/src/test/scala/com/typesafe/config/impl/TestUtils.scala
index e821797d..fcbfba66 100644
--- a/src/test/scala/com/typesafe/config/impl/TestUtils.scala
+++ b/src/test/scala/com/typesafe/config/impl/TestUtils.scala
@@ -134,6 +134,9 @@ abstract trait TestUtils {
         """{ "a" : ${a} }""", // simple cycle
         """[ { "a" : 2, "b" : ${${a}} } ]""", // nested substitution
         "[ = ]", // = is not a valid token
+        "{ include \"bar\" : 10 }", // include with a value after it
+        "{ include foo }", // include with unquoted string
+        "{ include : { \"a\" : 1 } }", // include used as unquoted key
         "") // empty document again, just for clean formatting of this list ;-)
 
     // We'll automatically try each of these with whitespace modifications
@@ -178,6 +181,11 @@ abstract trait TestUtils {
         "[ trux ]",
         "[ truex ]",
         "[ 10x ]", // number token with trailing junk
+        "{ include \"foo\" }", // valid include
+        "{ include\n\"foo\" }", // include with just a newline separating from string
+        "{ include\"foo\" }", // include with no whitespace after it
+        "[ include ]", // include can be a string value in an array
+        "{ foo : include }", // include can be a field value also
         "[ ${foo} ]",
         "[ ${\"foo\"} ]",
         "[ ${foo.bar} ]",