diff --git a/src/store/DelimitedKey.js b/src/store/DelimitedKey.js
new file mode 100644
index 0000000..004614b
--- /dev/null
+++ b/src/store/DelimitedKey.js
@@ -0,0 +1,134 @@
+/**
+ * Add and retrieve nested store values using string of delimited keys
+ *
+ * Copyright (C) 2017 R-T Specialty, LLC.
+ *
+ * This file is part of the Liza Data Collection Framework.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+'use strict';
+
+const { Trait, Class } = require( 'easejs' );
+const Store = require( './Store' );
+
+
+/**
+ * Add and retrieve items from (possibly) nested Stores
+ *
+ * This is a convenient syntax for deeply nested Stores and can greatly cut
+ * down on the verbosity of promises. This is best and least confusingly
+ * described with an example:
+ *
+ * @example
+ * const outer = Store.use( DelimitedKey( '.' ) )();
+ * const middle = Store();
+ * const inner = Store();
+ *
+ * // resolves to "inner value get"
+ * inner.add( 'foo', "inner value get" )
+ * .then( () => middle.add( 'inner', inner ) )
+ * .then( () => outer.add( 'middle', middle ) )
+ * .then( () => outer.get( 'middle.inner.foo' ) );
+ *
+ * // resolves to "inner value add"
+ * outer.add( 'middle.inner.foo', "inner value add" )
+ * .then( () => inner.get( 'foo' ) );
+ */
+module.exports = Trait( 'DelimitedKey' )
+ .implement( Store )
+ .extend(
+{
+ /**
+ * Key delimiter
+ * @type {string}
+ */
+ 'private _delim': '',
+
+
+ /**
+ * Specify key delimiter
+ *
+ * @param {string} delim key delimiter
+ */
+ __mixin( delim )
+ {
+ this._delim = ''+delim;
+ },
+
+
+ /**
+ * Add item to (possibly) nested store under with value `value`
+ *
+ * The given key `key` is split on the chosen delimiter (specified at
+ * the time of mixin). All but the last element in `key` are retrieved
+ * recursively as Stores; the final Store is then assigned `value` to
+ * the key represented by the last value in the delimited `key`.
+ *
+ * @param {string} key delimited store key
+ * @param {*} value value for key
+ *
+ * @return {Promise.} promise to add item to store, resolving to
+ * self (for chaining)
+ */
+ 'virtual abstract override public add'( key, value )
+ {
+ if ( typeof key !== 'string' )
+ {
+ return this.__super( key );
+ }
+
+ const parts = key.split( this._delim );
+ const maxi = parts.length - 1;
+ const __super = this.__super;
+
+ return parts
+ .reduce(
+ ( promise, part, i ) => promise.then( store =>
+ ( i < maxi ) ? store.get( part ) : store
+ ),
+ Promise.resolve( this )
+ )
+ .then( store => __super.call( this, parts[ maxi ], value ) );
+ },
+
+
+ /**
+ * Retrieve item from (possibly) nested store
+ *
+ * The given key `key` is split on the chosen delimiter (specified at
+ * the time of mixin). All but the last element in `key` are retrieved
+ * recursively as Stores; the final element in delimited `key` then
+ * identifies they key to be retrieved from the final Store.
+ *
+ * @param {string} key delimited store key
+ *
+ * @return {Promise} promise for the key value
+ */
+ 'virtual abstract override public get'( key )
+ {
+ if ( typeof key !== 'string' )
+ {
+ return this.__super( key );
+ }
+
+ const [ first, ...parts ] = key.split( this._delim );
+
+ return parts.reduce(
+ ( promise, part ) => promise.then( store => store.get( part ) ),
+ this.__super( first )
+ );
+ },
+} );
diff --git a/test/store/DelimitedKeyTest.js b/test/store/DelimitedKeyTest.js
new file mode 100644
index 0000000..d4ae044
--- /dev/null
+++ b/test/store/DelimitedKeyTest.js
@@ -0,0 +1,107 @@
+/**
+ * Tests DelimitedKey
+ *
+ * Copyright (C) 2017 R-T Specialty, LLC.
+ *
+ * This file is part of the Liza Data Collection Framework.
+ *
+ * liza is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+'use strict';
+
+const chai = require( 'chai' );
+const expect = chai.expect;
+
+chai.use( require( 'chai-as-promised' ) );
+
+const {
+ DelimitedKey: Sut,
+ MemoryStore: Store,
+ StoreMissError,
+} = require( '../../' ).store;
+
+
+
+describe( 'DelimitedKey', () =>
+{
+ describe( '#get', () =>
+ {
+ it( "retrieves nested store keys", () =>
+ {
+ const outer = Store.use( Sut( '.' ) )();
+ const middle = Store();
+ const inner = Store();
+ const inner_val = {};
+
+ return expect(
+ inner.add( 'foo', inner_val )
+ .then( () => middle.add( 'inner', inner ) )
+ .then( () => outer.add( 'middle', middle ) )
+ .then( () => outer.get( 'middle.inner.foo' ) )
+ ).to.eventually.equal( inner_val );
+ } );
+
+
+ it( "fails on unknown nested key", () =>
+ {
+ const outer = Store.use( Sut( '.' ) )();
+ const inner = Store();
+
+ return expect(
+ outer.add( 'inner', inner )
+ .then( () => outer.get( 'inner.foo.bar.baz' ) )
+ ).to.eventually.be.rejectedWith( StoreMissError, /[^.]foo\b/ );
+ } );
+
+
+ // rather than blowing up attempting to split
+ it( "fails gracefully on non-string key", () =>
+ {
+ return expect(
+ Store.use( Sut( '.' ) )().get( undefined )
+ ).to.eventually.be.rejectedWith( StoreMissError );
+ } );
+ } );
+
+
+ describe( '#add', () =>
+ {
+ it( "sets nested store keys", () =>
+ {
+ const outer = Store.use( Sut( '.' ) )();
+ const inner = Store();
+ const inner_val = {};
+
+ return expect(
+ inner.add( 'foo', inner_val )
+ .then( () => outer.add( 'inner', inner ) )
+ .then( () => outer.add( 'inner.foo', inner_val ) )
+ .then( () => inner.get( 'foo' ) )
+ ).to.eventually.equal( inner_val );
+ } );
+
+
+ it( "fails on unknown nested key", () =>
+ {
+ const outer = Store.use( Sut( '.' ) )();
+ const inner = Store();
+
+ return expect(
+ outer.add( 'inner', inner )
+ .then( () => outer.add( 'inner.none.foo', "fail" ) )
+ ).to.eventually.be.rejectedWith( StoreMissError, /[^.]none\b/ );
+ } );
+ } );
+} );