diff --git a/packages/provider/src/adapter-lit-element.js b/packages/provider/src/adapter-lit-element.js
index bcdf0929d479be253bd3c937117df3869dcc1fe6..c9112f0e4b449132fa0ce10257f8226980bb5ef8 100644
--- a/packages/provider/src/adapter-lit-element.js
+++ b/packages/provider/src/adapter-lit-element.js
@@ -13,9 +13,53 @@ export class AdapterLitElement extends LitElement {
         this.subscribe = '';
         this.unsubscribe = '';
 
+        this.callbackStore = [];
+
+        // Previously we used direct properties like this["lang"] (instead of this.propertyStore["lang"]) for storing the
+        // properties, but the "lang" property seems to be updated before the event from the MutationObserver, so we
+        // cannot observe a value change directly (as workaround we use another property (e.g. "langValue") instead of "lang")
+        this.propertyStore = {};
+
+        // We need to store our own "last values" because we cannot be sure what the MutationObserver detects
+        this.lastProperties = {};
+
         console.log('AdapterLitElement(' + this.tagName + ') constructor()');
     }
 
+    getProperty(name) {
+        return this.propertyStore[name];
+    }
+
+    getPropertyByAttributeName(name) {
+        return this[this.findPropertyName(name)];
+    }
+
+    setPropertyByAttributeName(name, value) {
+        this[this.findPropertyName(name)] = value;
+    }
+
+    setProperty(name, value) {
+        // TODO: check if lit attribute really present?
+        if (typeof value === 'object' && value !== null) {
+            // console.log("value is object", value);
+            this.setPropertyByAttributeName(name, value);
+        } else {
+            this.attributeChangedCallback(name, this.getPropertyByAttributeName(name), value);
+        }
+
+        this.lastProperties[name] = value;
+        this.propertyStore[name] = value;
+    }
+
+    hasPropertyChanged(name, value) {
+        return this.lastProperties[name] !== value;
+    }
+
+    hasProperty(name) {
+        // return this.hasAttribute("name")
+        return Object.hasOwnProperty.call(this.propertyStore, name);
+    }
+
     connectedCallback() {
         super.connectedCallback();
 
@@ -33,6 +77,99 @@ export class AdapterLitElement extends LitElement {
         }
 
         this.connected = true;
+
+        const that = this;
+
+        this.addEventListener('subscribe', function (e) {
+            const name = e.detail.name;
+            if (that.hasProperty(name) || that.root) {
+                console.log('AdapterLitElementProvider(' + that.tagName + ') eventListener("subscribe",..) name "' + name + '" found.');
+                that.callbackStore.push({name: name, callback: e.detail.callback, sender: e.detail.sender});
+
+                e.detail.callback(that.getProperty(name));
+                e.stopPropagation();
+            }
+        }, false);
+
+        this.addEventListener('unsubscribe', function (e) {
+            const name = e.detail.name;
+            const sender = e.detail.sender;
+            if (that.hasProperty(name) || that.root) {
+                console.log('AdapterLitElementProvider(' + that.tagName + ') eventListener("unsubscribe",..) name "' + name + '" found.');
+                that.callbackStore.forEach(item => {
+                    if (item.sender === sender && item.name === name) {
+                        const index = that.callbackStore.indexOf(item);
+                        that.callbackStore.splice(index, 1);
+                        console.log('AdapterLitElementProvider(' + that.tagName + ') eventListener for name "' + name + '" removed.');
+                    }
+                });
+
+                e.stopPropagation();
+            }
+        }, false);
+
+        // listen to property changes
+        this.addEventListener('set-property', function (e) {
+            const name = e.detail.name;
+            const value = e.detail.value;
+
+            if (that.hasProperty(name) || that.root) {
+                console.log('AdapterLitElementProvider(' + that.tagName + ') eventListener("set-property",..) name "' + name + '" found.');
+                that.setProperty(name, value);
+
+                that.callbackStore.forEach(item => {
+                    if (item.name === name) {
+                        item.callback(value);
+                    }
+                });
+
+                e.stopPropagation();
+            }
+        }, false);
+
+        // Options for the observer (which mutations to observe)
+        const config = { attributes: true, childList: false, subtree: false };
+
+        // Callback function to execute when mutations are observed
+        const callback = function(mutationsList, observer) {
+            // Use traditional 'for loops' for IE 11
+            for(const mutation of mutationsList) {
+                if (mutation.type === 'attributes') {
+                    const name = mutation.attributeName;
+                    const value = that.getAttribute(name);
+
+                    if (that.hasPropertyChanged(name, value)) {
+                        console.log('AdapterLitElementProvider (' + that.tagName + ') observed attribute "' + name + '" changed');
+                        that.setProperty(name, value);
+
+                        that.callbackStore.forEach(item => {
+                            if (item.name === name) {
+                                item.callback(value);
+                            }
+                        });
+                    }
+                }
+            }
+        };
+
+        // Create an observer instance linked to the callback function
+        const observer = new MutationObserver(callback);
+
+        // Start observing the target node for configured mutations
+        observer.observe(this, config);
+
+        // get all *not observed* attributes
+        if (this.hasAttributes()) {
+            const attrs = this.attributes;
+            for(let i = attrs.length - 1; i >= 0; i--) {
+                if (['id', 'class', 'style', 'data-tag-name'].includes(attrs[i].name)) {
+                    continue;
+                }
+
+                this.setProperty(attrs[i].name, attrs[i].value);
+                console.log('AdapterLitElementProvider (' + that.tagName + ') found attribute "' + attrs[i].name + '" = "' + attrs[i].value + '"');
+            }
+        }
     }
 
     subscribeProviderFor(element) {
@@ -49,16 +186,24 @@ export class AdapterLitElement extends LitElement {
                     name: global,
                     callback: (value) => {
                         console.log('AdapterLitElement(' + that.tagName + ') sub/Callback ' + global + ' -> ' + local + ' = ' + value);
-                        that.attributeChangedCallback(local, that[local], value);
 
-                        // check if an attribute also exists in the tag
-                        if (that.getAttribute(local) !== null) {
-                            // we don't support attributes and provider values at the same time
-                            console.warn('Provider callback: "' + local + '" is also an attribute in tag "' + that.tagName + '", this is not supported!');
+                        // If value is an object set it directly as property
+                        if (typeof value === 'object' && value !== null) {
+                            // console.log("value is object", value);
+                            that.setPropertyByAttributeName(local, value);
+                        } else {
+                            // console.log("local, that.getPropertyByAttributeName(local), value", local, that.getPropertyByAttributeName(local), value);
+                            that.attributeChangedCallback(local, that.getPropertyByAttributeName(local), value);
+
+                            // check if an attribute also exists in the tag
+                            if (that.getAttribute(local) !== null) {
+                                // we don't support attributes and provider values at the same time
+                                console.warn('Provider callback: "' + local + '" is also an attribute in tag "' + that.tagName + '", this is not supported!');
 
-                            // update attribute if reflectAttribute is enabled
-                            if (that.reflectAttribute) {
-                                that.setAttribute(local, value);
+                                // update attribute if reflectAttribute is enabled
+                                if (that.reflectAttribute) {
+                                    that.setAttribute(local, value);
+                                }
                             }
                         }
                     },
@@ -92,9 +237,27 @@ export class AdapterLitElement extends LitElement {
     }
 
     static getProperties(properties = {}) {
+        // TODO: super.properties doesn't seem to be defined here!
         return Object.assign(properties, super.properties);
     }
 
+    findPropertyName(attributeName) {
+        let resultName = attributeName;
+        const properties = this.constructor.properties;
+        // console.log("properties", properties);
+
+        for (const propertyName in properties) {
+            // console.log("findPropertyName", `${propertyName}: ${properties[propertyName]}`);
+            const attribute = properties[propertyName].attribute;
+            if (attribute === attributeName) {
+                resultName = propertyName;
+                break;
+            }
+        }
+
+        return resultName;
+    }
+
     attributeChangedCallback(name, oldValue, newValue) {
         switch(name) {
             case 'subscribe':