This closes #112
diff --git a/ui-modules/blueprint-composer/app/components/dsl-editor/dsl-editor.js b/ui-modules/blueprint-composer/app/components/dsl-editor/dsl-editor.js
index 6fb1d26..cf1e695 100644
--- a/ui-modules/blueprint-composer/app/components/dsl-editor/dsl-editor.js
+++ b/ui-modules/blueprint-composer/app/components/dsl-editor/dsl-editor.js
@@ -291,6 +291,18 @@
             };
         });
 
+        let params = entity.miscData.get('parameters').filter(param => param !== definition).map(param => {
+            return {
+                id: param.name,
+                type: DSL_KINDS.CONFIG,
+                entity: entity,
+                name: param.name,
+                description: param.description
+            };
+        });
+        
+        config = config.concat(params);
+
         config = Object.values(entity.getClusterMemberspecEntities()).reduce((acc, spec) => {
             return acc.concat(getConfigItems(spec, definition));
         }, config);
diff --git a/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js b/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
index a896aac..7cc63b0 100644
--- a/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
+++ b/ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
@@ -253,11 +253,13 @@
             entity.miscData.set('traits', []);
             deferred.resolve(entity);
             addUnlistedConfigKeysDefinitions(entity);
+            addUnlistedParameterDefinitions(entity);
         } else {
             entity.miscData.set('sensors', []);
             entity.miscData.set('traits', []);
             deferred.resolve(entity);
             addUnlistedConfigKeysDefinitions(entity);
+            addUnlistedParameterDefinitions(entity);
         }
 
         return deferred.promise;
@@ -534,6 +536,16 @@
         entity.miscData.set('config', allConfig);
     }
 
+    function addUnlistedParameterDefinitions(entity) {
+        let allParams = entity.miscData.get('parameters') || [];
+        entity.parameters.forEach((param) => {
+            if (!allParams.some((e) => e.name === param.name)) {
+                allParams.push(param);
+            }
+        });
+        entity.miscData.set('parameters', allParams);
+    }
+
     function populateEntityFromApiSuccess(entity, data) {
         entity.clearIssues({group: 'type'});
         entity.type = data.symbolicName;
@@ -545,6 +557,7 @@
         });
         entity.miscData.set('typeName', data.displayName || data.symbolicName);
         entity.miscData.set('config', data.config || []);
+        entity.miscData.set('parameters', data.parameters || []);
         entity.miscData.set('sensors', data.sensors || []);
         entity.miscData.set('traits', data.supertypes || []);
         entity.miscData.set('tags', data.tags || []);
@@ -555,6 +568,7 @@
         entity.miscData.set('ui-composer-hints', uiHints);
         entity.miscData.set('virtual', data.virtual || null);
         addUnlistedConfigKeysDefinitions(entity);
+        addUnlistedParameterDefinitions(entity);
         return entity;
     }
     function mergeAppendingLists(dst, src) {
@@ -574,11 +588,13 @@
         entity.addIssue(Issue.builder().group('type').message($sce.trustAsHtml(`Type <samp>${entity.type + (entity.hasVersion ? ':' + entity.version : '')}</samp> does not exist`)).build());
         entity.miscData.set('typeName', entity.type || '');
         entity.miscData.set('config', []);
+        entity.miscData.set('parameters', []);
         entity.miscData.set('sensors', []);
         entity.miscData.set('traits', []);
         entity.miscData.set('virtual', null);
         entity.icon = typeNotFoundIcon;
         addUnlistedConfigKeysDefinitions(entity);
+        addUnlistedParameterDefinitions(entity);
         return entity;
     }
 
diff --git a/ui-modules/blueprint-composer/app/components/util/model/entity.model.js b/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
index 9643c66..7d04410 100644
--- a/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
+++ b/ui-modules/blueprint-composer/app/components/util/model/entity.model.js
@@ -23,9 +23,9 @@
 const FIRST_MEMBERSPEC_REGEX = /^(\w+\.)*first[mM]ember[sS]pec$/;
 // TODO ideally we'd just look at type EntitySpec, not key name, but for now look at keyname, anything ending memberSpec
 const ANY_MEMBERSPEC_REGEX = /^(\w+\.)*(\w*)[mM]ember[sS]pec$/;
-const RESERVED_KEY_REGEX = /(^children$|^services$|^locations?$|^brooklyn\.config$|^brooklyn\.enrichers$|^brooklyn\.policies$)/;
+const RESERVED_KEY_REGEX = /(^children$|^services$|^locations?$|^brooklyn\.config$|^brooklyn\.parameters$|^brooklyn\.enrichers$|^brooklyn\.policies$)/;
 const FIELD = {
-    SERVICES: 'services', CHILDREN: 'brooklyn.children', CONFIG: 'brooklyn.config', LOCATION: 'location',
+    SERVICES: 'services', CHILDREN: 'brooklyn.children', CONFIG: 'brooklyn.config', PARAMETERS: 'brooklyn.parameters', LOCATION: 'location',
     POLICIES: 'brooklyn.policies', ENRICHERS: 'brooklyn.enrichers', TYPE: 'type', NAME: 'name', ID: 'id',
     // This field is not part of the Brooklyn blueprint spec but used to store information about the composer, e.g. X,Y coordinates, virtual items, etc
     COMPOSER_META: 'brooklyn.composer.metadata'
@@ -50,6 +50,7 @@
 const PARENT = new WeakMap();
 const METADATA = new WeakMap();
 const CONFIG = new WeakMap();
+const PARAMETERS = new WeakMap();
 const CHILDREN = new WeakMap();
 const LOCATIONS = new WeakMap();
 const POLICIES = new WeakMap();
@@ -69,6 +70,7 @@
     constructor() {
         ID.set(this, Math.random().toString(36).slice(2));
         CONFIG.set(this, new Map());
+        PARAMETERS.set(this, new Map());
         METADATA.set(this, new Map());
         ENRICHERS.set(this, new Map());
         POLICIES.set(this, new Map());
@@ -321,6 +323,10 @@
         return CONFIG.get(this);
     }
 
+    get parameters() {
+        return PARAMETERS.get(this);
+    }
+
     get metadata() {
         return METADATA.get(this);
     }
@@ -474,6 +480,14 @@
     }
 
     /**
+     * Has {Entity} got parameters
+     * @returns {boolean}
+     */
+    hasParameters() {
+        return PARAMETERS.get(this).size > 0;
+    }
+
+    /**
      * Has {Entity} got a location
      * @returns {boolean}
      */
@@ -544,6 +558,9 @@
 Entity.prototype.getConfigAsJson = getConfigAsJson;
 Entity.prototype.setConfigFromJson = setConfigFromJson;
 
+Entity.prototype.getParametersAsArray = getParametersAsArray;
+Entity.prototype.setParametersFromJson = setParametersFromJson;
+
 Entity.prototype.getMetadataAsJson = getMetadataAsJson;
 Entity.prototype.setMetadataFromJson = setMetadataFromJson;
 
@@ -552,8 +569,10 @@
 
 Entity.prototype.getData = getData;
 Entity.prototype.addConfig = addConfig;
+Entity.prototype.addParameter = addParameter;
 Entity.prototype.addMetadata = addMetadata;
 Entity.prototype.removeConfig = removeConfig;
+Entity.prototype.removeParameter = removeParameter;
 Entity.prototype.removeMetadata = removeMetadata;
 Entity.prototype.isCluster = isCluster;
 Entity.prototype.isMemberSpec = isMemberSpec;
@@ -596,6 +615,13 @@
     }
 }
 
+function addParameter(param) {
+    let key = param.name;
+    PARAMETERS.get(this).set(key, param);
+    this.touch();
+    return this;
+}
+
 function addMetadata(key, value) {
     if (!RESERVED_KEY_REGEX.test(key)) {
         METADATA.get(this).set(key, value);
@@ -619,6 +645,17 @@
 }
 
 /**
+ * Remove an entry from brooklyn.parameters
+ * @param {string} key
+ * @returns {Entity}
+ */
+function removeParameter(key) {
+    PARAMETERS.get(this).delete(key);
+    this.touch();
+    return this;
+}
+
+/**
  * Remove an entry from the entity metadata
  * @param {string} key
  * @returns {Entity}
@@ -734,6 +771,9 @@
     if (this.hasConfig()) {
         result[FIELD.CONFIG] = this.getConfigAsJson();
     }
+    if (this.hasParameters()) {
+        result[FIELD.PARAMETERS] = this.getParametersAsArray();
+    }
     if (this.hasLocation()) {
         result.location = LOCATIONS.get(this);
     }
@@ -845,6 +885,7 @@
     ID.set(this, Math.random().toString(36).slice(2));
     this.removeLocation();
     CONFIG.set(this, new Map());
+    PARAMETERS.set(this, new Map());
     METADATA.set(this, new Map());
     ENRICHERS.set(this, new Map());
     POLICIES.set(this, new Map());
@@ -896,6 +937,9 @@
             case FIELD.CONFIG:
                 self.setConfigFromJson(incomingModel[key]);
                 break;
+            case FIELD.PARAMETERS:
+                self.setParametersFromJson(incomingModel[key]);
+                break;
             case FIELD.ENRICHERS:
                 self.setEnrichersFromJson(incomingModel[key]);
                 break;
@@ -964,6 +1008,22 @@
     this.touch();
 }
 
+/**
+ * Set brooklyn.parameters from JSON {Array}
+ * @param {Array} incomingModel
+ */
+function setParametersFromJson(incomingModel) {
+    if (!Array.isArray(incomingModel)) {
+        throw new Error('Model parse error ... cannot add parameters as it must be an array')
+    }
+    PARAMETERS.get(this).clear();
+    var self = this;
+    incomingModel.map((param)=> {
+        self.addParameter(param);
+    });
+    this.touch();
+}
+
 
 function setMetadataFromJson(incomingModel) {
     METADATA.get(this).clear();
@@ -1022,6 +1082,10 @@
     return cleanForJson(CONFIG.get(this), -1);
 }
 
+function getParametersAsArray() {
+    return Array.from(PARAMETERS.get(this).values());
+}
+
 /* "cleaning" here means:  Dsl objects are toStringed, to the given depth (or infinite if depth<0);
  * and entries in Map that are memberspec are unwrapped.
  * previously we also stringified maps/lists but that seemed pointless, and it was lossy and buggy.