diff --git a/eraser-base/src/main/jastadd/Item.jrag b/eraser-base/src/main/jastadd/Item.jrag
index e7b6bfb808eb4f1c40ce86442f85340ae8f1ebf7..0ded5474bca071a4ba360e2491b8c633ba91df11 100644
--- a/eraser-base/src/main/jastadd/Item.jrag
+++ b/eraser-base/src/main/jastadd/Item.jrag
@@ -287,7 +287,7 @@ aspect ItemHandling {
 
   //--- stateUpdated ---
   /**
-   * Called, whenever the state of an item is updated. Does various things including:
+   * Called, whenever the state of an item is updated. Does various things (except it has no parent) including:
    * <ul>
    *   <li>Send the new state via MQTT</li>
    *   <li>Send the new state to Influx DB</li>
@@ -296,6 +296,7 @@ aspect ItemHandling {
    * @param shouldSendState whether to send the new state (currently affects MQTT and Influx)
    */
   protected void Item.stateUpdated(boolean shouldSendState) {
+    if (getParent() == null) { return; }
     if (shouldSendState) {
       try {
         // sendState() refined in MQTT and Influx aspect
@@ -304,7 +305,7 @@ aspect ItemHandling {
         logger.catching(e);
       }
     }
-    if (this.getStateData().checkStateProcessingTime(getRelevantItemPerformance())) {
+    if (this.getStateData().checkStateProcessingTime(relevantItemPerformance())) {
       this.getStateData().afterStateChangeProcessed();
       getItemObserver().apply();
     }
diff --git a/eraser-base/src/main/jastadd/Navigation.jrag b/eraser-base/src/main/jastadd/Navigation.jrag
index 1e73d8b151a03e792af75458369000f40cdca1eb..42fd1bf89ed8a972d68af4ab1e7ac1b5c956ef56 100644
--- a/eraser-base/src/main/jastadd/Navigation.jrag
+++ b/eraser-base/src/main/jastadd/Navigation.jrag
@@ -11,21 +11,29 @@ aspect Navigation {
     return result;
   }
 
-  protected ItemPerformance GroupItemComposite.getRelevantItemPerformance() {
-    ASTNode parent = getParent();
-    //TODO: Remove try catch
-    try {
-      Group g = this.getEnclosingGroup();
-      if (this.getItemPerformance()==null && g!=null) {
-        return g.getRelevantItemPerformance();
-      }
-    } catch(Exception e) {
-
+  inh ItemPerformance Item.relevantItemPerformance();
+  inh ItemPerformance Group.relevantItemPerformance();
+  eq Group.getItem(int index).relevantItemPerformance() {
+    Item item = getItem(index);
+    // first, use value defined on item itself, if any
+    if (item.hasItemPerformance()) {
+      return item.getItemPerformance();
+    }
+    // then on this group, if defined
+    if (this.hasItemPerformance()) {
+      return this.getItemPerformance();
+    }
+    // recursively use enclosing group and use value from there, if any
+    Group parent = getEnclosingGroup();
+    if (parent != null) {
+      return parent.relevantItemPerformance();
     }
-    return this.getItemPerformance();
+    // if top-level group without ItemPerformance
+    return null;
   }
 
-  inh Group GroupItemComposite.getEnclosingGroup();
+  inh Group Group.getEnclosingGroup();
+  inh Group Item.getEnclosingGroup();
 
   private void SmartHomeEntityModel.addItems(java.util.List<Item> result, JastAddList<Group> groups) {
     groups.forEach(group -> group.getItemList().forEach(item -> result.add(item)));
diff --git a/eraser-base/src/main/jastadd/Rules.relast b/eraser-base/src/main/jastadd/Rules.relast
index 8746ae62081ec92c6d203253032acc831cad06d8..e695d9250bf890d80657b027aee7ecde1dd57343 100644
--- a/eraser-base/src/main/jastadd/Rules.relast
+++ b/eraser-base/src/main/jastadd/Rules.relast
@@ -2,7 +2,8 @@
 Rule ::= Condition* Action* ;
 abstract Condition ;
 ItemStateCheckCondition : Condition ::= ItemStateCheck ;
-ItemStateChangeCondition : Condition ::= Item;
+ItemStateChangeCondition : Condition ;
+rel ItemStateChangeCondition.Item -> Item;
 ExpressionCondition : Condition ::= LogicalExpression ;
 abstract Action ;
 NoopAction : Action ;
diff --git a/eraser-base/src/main/jastadd/eraser.parser b/eraser-base/src/main/jastadd/eraser.parser
index 63ad20d42f9edc3424b472bccf4e072d78b6e0a1..a5aa61240c0c0eba0daec6286ebadafb9af68291 100644
--- a/eraser-base/src/main/jastadd/eraser.parser
+++ b/eraser-base/src/main/jastadd/eraser.parser
@@ -41,6 +41,7 @@ Root goal =
   |  influx_root.ir goal.r              {: r.setInfluxRoot(ir); return r; :}
   |  machine_learning_root.ml goal.r    {: r.setMachineLearningRoot(ml); return r; :}
   |  rule.rule goal.r                   {: r.addRule(rule); return r; :}
+  |  item_performance.ip goal.r         {: r.addItemPerformance(ip); return r; :}
   |  thing.t                            {: return eph.createRoot(t); :}
   |  item.i                             {: return eph.createRoot(); :}
   |  group.g                            {: return eph.createRoot(g); :}
@@ -53,7 +54,7 @@ Root goal =
   |  influx_root.ir                     {: return eph.createRoot(ir); :}
   |  machine_learning_root.ml           {: return eph.createRoot(ml); :}
   |  rule.rule                          {: return eph.createRoot(rule); :}
-  |  item_performance.ip           {: return eph.createRoot(ip); :}
+  |  item_performance.ip                {: return eph.createRoot(ip); :}
   ;
 
 %left RB_ROUND;
@@ -129,29 +130,28 @@ Item item =
   |  ITEM COLON item_body.ib SEMICOLON                {: return eph.retype(new DefaultItem(), ib); :}
   ;
 
-// ITEM_TYPE Item: id="" label="" state="" category="" topic="" metaData={"key":"value"} ;
+// ITEM_TYPE Item: id="" label="" state="" category="" topic="" performance="" metaData={"key":"value"} ;
 Item item_body =
      ID EQUALS TEXT.n item_body.i       {: return eph.setID(i, n); :}
   |  LABEL EQUALS TEXT.n item_body.i    {: i.setLabel(n); return i; :}
   |  STATE EQUALS TEXT.n item_body.i    {: i.setStateFromString(n); return i; :}
   |  TOPIC EQUALS TEXT.n item_body.i    {: return eph.setTopic(i, n); :}
   |  CATEGORY EQUALS TEXT.n item_body.i {: return eph.setCategory(i, n); :}
-  |  PERFORMANCE EQUALS TEXT.n item_body.i {: return eph.setPerformance(i, n); :}
+  |  PERFORMANCE EQUALS item_performance_ref.ip item_body.i           {: i.setItemPerformance(ip); return i; :}
   |  META_DATA EQUALS string_map.md item_body.i
     {: return eph.setMetaData(i, md); :}
   |                                     {: return eph.createItem(); :}
   ;
 
-Item item_ref =
-     TEXT.n                                 {: return Item.createRef(n); :}
-  ;
+Item item_ref = TEXT.n {: return Item.createRef(n); :};
+ItemPerformance item_performance_ref = TEXT.n {: return ItemPerformance.createRef(n); :};
 
 Group group =
      GROUP COLON group_body.gb SEMICOLON    {: return gb; :}
   ;
 
-// Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation="";
-// Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] aggregation="" ("","");
+// Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] performance="" aggregation="";
+// Group: id="" groups=["GROUP_ID", "GROUP_ID"] items=["ITEM_ID", "ITEM_ID"] performance="" aggregation="" ("","");
 Group group_body =
      ID EQUALS TEXT.n group_body.g                    {: return eph.setID(g, n); :}
   |  LABEL EQUALS TEXT.n group_body.g                 {: g.setLabel(n); return g; :}
@@ -160,7 +160,7 @@ Group group_body =
   |  AGGREGATION EQUALS TEXT.n group_body.g           {: return eph.setSimpleAggregationFunction(g, n); :}
   |  AGGREGATION EQUALS TEXT.n round_string_list.params group_body.g
     {: return eph.setParameterizedAggregationFunction(g, n, params); :}
-  |  PERFORMANCE EQUALS TEXT.n group_body.g           {: return eph.setPerformance(g, n); :}
+  |  PERFORMANCE EQUALS item_performance_ref.ip group_body.g           {: g.setItemPerformance(ip); return g; :}
   |                                                   {: return new Group(); :}
   ;
 
@@ -378,4 +378,4 @@ ItemPerformance item_performance_body =
      ID EQUALS TEXT.n item_performance_body.ip                  {: return eph.setID(ip, n); :}
   |  PROCESS_FREQUENCY EQUALS TEXT.n item_performance_body.ip        {: ip.setEventProcessingFrequency(Double.parseDouble(n)); return ip; :}
   |                                                   {: return new ItemPerformance(); :}
-  ;
\ No newline at end of file
+  ;
diff --git a/eraser-base/src/main/jastadd/shem.relast b/eraser-base/src/main/jastadd/shem.relast
index ee3f42d0cf3f61691ee16f1936f6e8547911ed41..250c5714daf2a79e6846b7f51bb8a4dfb662f332 100644
--- a/eraser-base/src/main/jastadd/shem.relast
+++ b/eraser-base/src/main/jastadd/shem.relast
@@ -25,12 +25,10 @@ rel Channel.LinkedItem* <-> Item.Channel? ;
 
 Parameter : DescribableModelElement ::= <Type:ParameterValueType> [DefaultValue:ParameterDefaultValue] <Context:String> <Required:boolean> ;
 ParameterDefaultValue ::= <Value:String> ;
-abstract GroupItemComposite : LabelledModelElement ;
-rel GroupItemComposite.ItemPerformance -> ItemPerformance ;
 
-abstract Item : GroupItemComposite ::= <_fetched_data:boolean> MetaData:ItemMetaData* /ItemObserver/ /StateData/;
+abstract Item : LabelledModelElement ::= <_fetched_data:boolean> MetaData:ItemMetaData* /ItemObserver/ /StateData/;
 rel Item.Category? -> ItemCategory ;
-
+rel Item.ItemPerformance? -> ItemPerformance ;
 
 abstract ItemWithBooleanState : Item ::= <_state:boolean> ;
 abstract ItemWithStringState : Item ::= <_state:String> ;
@@ -56,7 +54,9 @@ ItemCategory ::= <Name:String> ;
 StateData ::= <LastChangeDate:Instant> ;
 
 
-Group : GroupItemComposite ::= Group* Item* [AggregationFunction:GroupAggregationFunction] ;
+Group : LabelledModelElement ::= Group* Item* [AggregationFunction:GroupAggregationFunction] ;
+rel Group.ItemPerformance? -> ItemPerformance ;
+
 abstract GroupAggregationFunction ;
 SimpleGroupAggregationFunction : GroupAggregationFunction ::= <FunctionName:SimpleGroupAggregationFunctionName> ;
 ParameterizedGroupAggregationFunction : GroupAggregationFunction ::= <FunctionName:ParameterizedGroupAggregationFunctionName>
diff --git a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
index 3f6b1df53f0709793100d72b619896ead298a3d4..f5eeee1dac81c08d7f4bd4f7e686ca098b4726b2 100644
--- a/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
+++ b/eraser-base/src/main/java/de/tudresden/inf/st/eraser/parser/EraserParserHelper.java
@@ -38,7 +38,6 @@ public class EraserParserHelper {
   private Map<Item, Iterable<String>> missingControllingListMap = new HashMap<>();
   private Map<Group, Iterable<String>> missingSubGroupListMap = new HashMap<>();
   private Map<Group, Iterable<String>> missingItemListMap = new HashMap<>();
-  private Map<GroupItemComposite, String> missingItemPerformanceMap = new HashMap<>();
   private Map<ThingType, Iterable<String>> missingChannelTypeListMap = new HashMap<>();
   private Map<ThingType, Iterable<String>> missingParameterListMap = new HashMap<>();
 
@@ -97,7 +96,6 @@ public class EraserParserHelper {
     resolveList(itemMap, missingItemLinkListMap, Channel::addLinkedItem);
     resolveList(groupMap, missingSubGroupListMap, Group::addGroup);
     resolveList(itemMap, missingItemListMap, this::addItemToGroup);
-    resolve(itemPerformanceMap, missingItemPerformanceMap, this::setPerformanceOnItem);
     resolveList(channelTypeMap, missingChannelTypeListMap, ThingType::addChannelType);
     resolveList(parameterMap, missingParameterListMap, ThingType::addParameter);
     resolveList(itemMap, missingControllingListMap, Item::addControlling);
@@ -118,10 +116,6 @@ public class EraserParserHelper {
     group.addItem(item);
   }
 
-  private void setPerformanceOnItem(GroupItemComposite performanceElement, ItemPerformance itemPerformance) {
-    performanceElement.setItemPerformance(itemPerformance);
-  }
-
   private void fillUnused() {
     unusedElements.addAll(thingTypeMap.values());
     unusedElements.addAll(channelTypeMap.values());
@@ -304,13 +298,6 @@ public class EraserParserHelper {
     return item;
   }
 
-  public GroupItemComposite setPerformance(GroupItemComposite performanceElement, String performanceName) {
-    missingItemPerformanceMap.put(performanceElement, performanceName);
-    return performanceElement;
-  }
-
-
-
   public Item setMetaData(Item item, StringKeyMap metaData) {
     for (AbstractMap.SimpleEntry<String, String> entry : metaData) {
       item.addMetaData(new ItemMetaData(entry.getKey(), entry.getValue()));