"561698 -  Merge 'org.eclipse.mdm.api.default/mkoller/contrib' into 'mkoller/contrib'"

Signed-off-by: Simon Skoczylas <simon.skoczylas@karakun.com>
diff --git a/org.eclipse.mdm.api.base/.gitignore b/org.eclipse.mdm.api.base/.gitignore
new file mode 100644
index 0000000..49678ad
--- /dev/null
+++ b/org.eclipse.mdm.api.base/.gitignore
@@ -0,0 +1,17 @@
+# eclipse
+.classpath
+.project
+.settings/
+bin/
+
+# gradle
+.gradle
+build/
+
+# intellij
+.idea/
+out/
+*.ipr
+*.iml
+*.iws
+/bin/
diff --git a/org.eclipse.mdm.api.base/LICENSE.txt b/org.eclipse.mdm.api.base/LICENSE.txt
new file mode 100644
index 0000000..e48e096
--- /dev/null
+++ b/org.eclipse.mdm.api.base/LICENSE.txt
@@ -0,0 +1,277 @@
+Eclipse Public License - v 2.0
+
+    THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
+    PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
+    OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a) in the case of the initial Contributor, the initial content
+     Distributed under this Agreement, and
+
+  b) in the case of each subsequent Contributor:
+     i) changes to the Program, and
+     ii) additions to the Program;
+  where such changes and/or additions to the Program originate from
+  and are Distributed by that particular Contributor. A Contribution
+  "originates" from a Contributor if it was added to the Program by
+  such Contributor itself or anyone acting on such Contributor's behalf.
+  Contributions do not include changes or additions to the Program that
+  are not Modified Works.
+
+"Contributor" means any person or entity that Distributes the Program.
+
+"Licensed Patents" mean patent claims licensable by a Contributor which
+are necessarily infringed by the use or sale of its Contribution alone
+or when combined with the Program.
+
+"Program" means the Contributions Distributed in accordance with this
+Agreement.
+
+"Recipient" means anyone who receives the Program under this Agreement
+or any Secondary License (as applicable), including Contributors.
+
+"Derivative Works" shall mean any work, whether in Source Code or other
+form, that is based on (or derived from) the Program and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship.
+
+"Modified Works" shall mean any work in Source Code or other form that
+results from an addition to, deletion from, or modification of the
+contents of the Program, including, for purposes of clarity any new file
+in Source Code form that contains any contents of the Program. Modified
+Works shall not include works that contain only declarations,
+interfaces, types, classes, structures, or files of the Program solely
+in each case in order to link to, bind by name, or subclass the Program
+or Modified Works thereof.
+
+"Distribute" means the acts of a) distributing or b) making available
+in any manner that enables the transfer of a copy.
+
+"Source Code" means the form of a Program preferred for making
+modifications, including but not limited to software source code,
+documentation source, and configuration files.
+
+"Secondary License" means either the GNU General Public License,
+Version 2.0, or any later versions of that license, including any
+exceptions or additional permissions as identified by the initial
+Contributor.
+
+2. GRANT OF RIGHTS
+
+  a) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free copyright
+  license to reproduce, prepare Derivative Works of, publicly display,
+  publicly perform, Distribute and sublicense the Contribution of such
+  Contributor, if any, and such Derivative Works.
+
+  b) Subject to the terms of this Agreement, each Contributor hereby
+  grants Recipient a non-exclusive, worldwide, royalty-free patent
+  license under Licensed Patents to make, use, sell, offer to sell,
+  import and otherwise transfer the Contribution of such Contributor,
+  if any, in Source Code or other form. This patent license shall
+  apply to the combination of the Contribution and the Program if, at
+  the time the Contribution is added by the Contributor, such addition
+  of the Contribution causes such combination to be covered by the
+  Licensed Patents. The patent license shall not apply to any other
+  combinations which include the Contribution. No hardware per se is
+  licensed hereunder.
+
+  c) Recipient understands that although each Contributor grants the
+  licenses to its Contributions set forth herein, no assurances are
+  provided by any Contributor that the Program does not infringe the
+  patent or other intellectual property rights of any other entity.
+  Each Contributor disclaims any liability to Recipient for claims
+  brought by any other entity based on infringement of intellectual
+  property rights or otherwise. As a condition to exercising the
+  rights and licenses granted hereunder, each Recipient hereby
+  assumes sole responsibility to secure any other intellectual
+  property rights needed, if any. For example, if a third party
+  patent license is required to allow Recipient to Distribute the
+  Program, it is Recipient's responsibility to acquire that license
+  before distributing the Program.
+
+  d) Each Contributor represents that to its knowledge it has
+  sufficient copyright rights in its Contribution, if any, to grant
+  the copyright license set forth in this Agreement.
+
+  e) Notwithstanding the terms of any Secondary License, no
+  Contributor makes additional grants to any Recipient (other than
+  those set forth in this Agreement) as a result of such Recipient's
+  receipt of the Program under the terms of a Secondary License
+  (if permitted under the terms of Section 3).
+
+3. REQUIREMENTS
+
+3.1 If a Contributor Distributes the Program in any form, then:
+
+  a) the Program must also be made available as Source Code, in
+  accordance with section 3.2, and the Contributor must accompany
+  the Program with a statement that the Source Code for the Program
+  is available under this Agreement, and informs Recipients how to
+  obtain it in a reasonable manner on or through a medium customarily
+  used for software exchange; and
+
+  b) the Contributor may Distribute the Program under a license
+  different than this Agreement, provided that such license:
+     i) effectively disclaims on behalf of all other Contributors all
+     warranties and conditions, express and implied, including
+     warranties or conditions of title and non-infringement, and
+     implied warranties or conditions of merchantability and fitness
+     for a particular purpose;
+
+     ii) effectively excludes on behalf of all other Contributors all
+     liability for damages, including direct, indirect, special,
+     incidental and consequential damages, such as lost profits;
+
+     iii) does not attempt to limit or alter the recipients' rights
+     in the Source Code under section 3.2; and
+
+     iv) requires any subsequent distribution of the Program by any
+     party to be under a license that satisfies the requirements
+     of this section 3.
+
+3.2 When the Program is Distributed as Source Code:
+
+  a) it must be made available under this Agreement, or if the
+  Program (i) is combined with other material in a separate file or
+  files made available under a Secondary License, and (ii) the initial
+  Contributor attached to the Source Code the notice described in
+  Exhibit A of this Agreement, then the Program may be made available
+  under the terms of such Secondary Licenses, and
+
+  b) a copy of this Agreement must be included with each copy of
+  the Program.
+
+3.3 Contributors may not remove or alter any copyright, patent,
+trademark, attribution notices, disclaimers of warranty, or limitations
+of liability ("notices") contained within the Program from any copy of
+the Program which they Distribute, provided that Contributors may add
+their own appropriate notices.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain responsibilities
+with respect to end users, business partners and the like. While this
+license is intended to facilitate the commercial use of the Program,
+the Contributor who includes the Program in a commercial product
+offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes
+the Program in a commercial product offering, such Contributor
+("Commercial Contributor") hereby agrees to defend and indemnify every
+other Contributor ("Indemnified Contributor") against any losses,
+damages and costs (collectively "Losses") arising from claims, lawsuits
+and other legal actions brought by a third party against the Indemnified
+Contributor to the extent caused by the acts or omissions of such
+Commercial Contributor in connection with its distribution of the Program
+in a commercial product offering. The obligations in this section do not
+apply to any claims or Losses relating to any actual or alleged
+intellectual property infringement. In order to qualify, an Indemnified
+Contributor must: a) promptly notify the Commercial Contributor in
+writing of such claim, and b) allow the Commercial Contributor to control,
+and cooperate with the Commercial Contributor in, the defense and any
+related settlement negotiations. The Indemnified Contributor may
+participate in any such claim at its own expense.
+
+For example, a Contributor might include the Program in a commercial
+product offering, Product X. That Contributor is then a Commercial
+Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Contributor's responsibility
+alone. Under this section, the Commercial Contributor would have to
+defend claims against the other Contributors related to those performance
+claims and warranties, and if a court requires any other Contributor to
+pay any damages as a result, the Commercial Contributor must pay
+those damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
+BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
+IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
+TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
+PURPOSE. Each Recipient is solely responsible for determining the
+appropriateness of using and distributing the Program and assumes all
+risks associated with its exercise of rights under this Agreement,
+including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs
+or equipment, and unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
+PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
+SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
+PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
+EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+7. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against any entity
+(including a cross-claim or counterclaim in a lawsuit) alleging that the
+Program itself (excluding combinations of the Program with other software
+or hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and survive.
+
+Everyone is permitted to copy and distribute copies of this Agreement,
+but in order to avoid inconsistency the Agreement is copyrighted and
+may only be modified in the following manner. The Agreement Steward
+reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement
+Steward has the right to modify this Agreement. The Eclipse Foundation
+is the initial Agreement Steward. The Eclipse Foundation may assign the
+responsibility to serve as the Agreement Steward to a suitable separate
+entity. Each new version of the Agreement will be given a distinguishing
+version number. The Program (including Contributions) may always be
+Distributed subject to the version of the Agreement under which it was
+received. In addition, after a new version of the Agreement is published,
+Contributor may elect to Distribute the Program (including its
+Contributions) under the new version.
+
+Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
+receives no rights or licenses to the intellectual property of any
+Contributor under this Agreement, whether expressly, by implication,
+estoppel or otherwise. All rights in the Program not expressly granted
+under this Agreement are reserved. Nothing in this Agreement is intended
+to be enforceable by any entity that is not a Contributor or Recipient.
+No third-party beneficiary rights are created under this Agreement.
+
+Exhibit A - Form of Secondary Licenses Notice
+
+"This Source Code may also be made available under the following
+Secondary Licenses when the conditions for such availability set forth
+in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
+version(s), and exceptions or additional permissions here}."
+
+  Simply including a copy of this Agreement, including this Exhibit A
+  is not sufficient to license the Source Code under Secondary Licenses.
+
+  If it is not possible or desirable to put the notice in a particular
+  file, then You may include the notice in a location (such as a LICENSE
+  file in a relevant directory) where a recipient would be likely to
+  look for such a notice.
+
+  You may add additional accurate notices of copyright ownership.
diff --git a/org.eclipse.mdm.api.base/NOTICE.txt b/org.eclipse.mdm.api.base/NOTICE.txt
new file mode 100644
index 0000000..56281c6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/NOTICE.txt
@@ -0,0 +1,382 @@
+# Notices for Eclipse MDM|BL
+
+This content is produced and maintained by the Eclipse MDM|BL project,
+it is a project of the openMDM(R) Eclipse Working Group.
+
+* Project home: https://projects.eclipse.org/projects/technology.mdmbl
+
+## Trademarks
+
+Eclipse MDM|BL, MDM|BL and Eclipse openMDM(R) logo are registered trademarks
+of the Eclipse Foundation.
+
+## Copyright
+
+All content is the property of the following respective authors or their employers.
+For more information regarding authorship of content, please consult the listed
+source code repository logs.
+
+Copyright (c) 2016-2019 Gigatronik Ingolstadt GmbH
+Copyright (c) 2016-2020 Peak Solution GmbH
+Copyright (c) 2017-2018 science + computing AG Tuebingen (ATOS SE)
+Copyright (c) 2017-2018 Canoo Engineering AG
+Copyright (c) 2017 Florian Schmitt
+Copyright (c) 2017-2020 Angelika Wittek
+Copyright (c) 2018-2019 Elektronische Fahrwerksysteme GMBH
+Copyright (c) 2018-2020 Karakun AG
+Copyright (c) 2018-2020 Alexander Nehmer
+
+## Declared Project Licenses
+
+This program and the accompanying materials are made available under the
+terms of the Eclipse Public License v. 2.0 which is available at
+http://www.eclipse.org/legal/epl-2.0.
+
+SPDX-License-Identifier: EPL-2.0
+
+## Source Code
+
+The project maintains the following source code repositories:
+
+org.eclipse.mdm.api.base.git	    - The openMDM(R) API.
+org.eclipse.mdm.api.default.git	    - Extension of the openMDM(R) API containing default elements.
+org.eclipse.mdm.api.odsadapter.git	- ODS implementation of persistence adapter.
+org.eclipse.mdm.nucleus.git	        - Core building blocks for the openMDM Business Logic and Web Frontend.
+
+## Third-party Content
+
+The Content includes items that have been sourced from third parties as set out below.
+If you did not receive this Content directly from the Eclipse Foundation, the following
+is provided for informational purposes only, and you should look to
+the Redistributor's license for terms and conditions of use.
+
+antlr4-4.5.3.jar(2.5.3)
+    * License: New BSD license
+
+aopalliance-repackaged-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+commons-codec-1.2.jar (1.2)
+    * License: Apache License, 2.0
+
+commons-httpclient-3.1.jar  (3.1)
+    * License: Apache License, 2.0
+
+commons-lang3-3.8.1.jar (3.8.1)
+    * License: Apache License, 2.0
+
+commons-text-1.6.jar (1.6)
+    * License: Apache License, 2.0
+
+gson-2.7.jar (2.7)
+    * License: Apache License, 2.0
+
+Google Guava Version: 25.0-jre  (25.0)
+    * License: Apache License, 2.0
+
+Gradle Wrapper (4.10.2)
+    * License: Apache License, 2.0
+
+hk2-api-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL-1.1
+
+hk2-locator-2.5.0-b05.jar(2.5.0-b05)
+    * License: CDDL
+
+hk2-utils-2.5.0-b05.jar (2.5.0-b05)
+    * License: CDDL
+
+jackson-annotations-2.9.0.jar  (2.9.0)
+    * License: Apache License, 2.0
+
+jackson-core-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-databind-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-base-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-jaxrs-json-provider-2.9.2.jar(2.9.2)
+    * License: Apache License, 2.0
+
+jackson-module-jaxb-annotations-2.9.2.jar  (2.9.2)
+    * License: Apache License, 2.0
+
+javassist-3.20.0-GA.jar  (2.20.0-GA)
+    * License: Apache 2.0
+
+jcl-over-slf4j-1.7.25.jar(1.7.25)
+    * License: MIT License
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL:  https://www.slf4j.org
+    * Source URL:   https://github.com/qos-ch/slf4j
+
+jersey-client-2.23.2.jar (2.23.2)
+     * License: CDDL
+
+jersey-common-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-2.23.2.jar  (2.23.2)
+    * License: CDDL
+
+jersey-container-servlet-core-2.23.3.jar(2.23.2)
+    * License: CDDL
+
+jersey-guava-2.23.2.jar  (2.23.2)
+    * License: Apache License, 2.0
+
+jersey-media-jaxb-2.23.2.jar(2.23.2)
+    * License: CDDL
+
+jersey-media-sse-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-media-multipart-2.23.2.jar (2.23.2)
+    * License: CDDL
+
+jersey-server-2.23.2.jar (2.23.2)
+    * License: Apache-2.0
+
+log4j-over-slf4j-1.7.25.jar (1.7.25)
+    * License: Apache-2.0
+
+logback-classic-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+logback-core-1.2.3.jar(1.2.3)
+    * License: Eclipse Public License 1.0
+
+mimepull-1.9.6.jar (1.9.4)
+    * License: CDDL
+
+openatfx-0.7.4.jar (0.7.4)
+    * License: Apache-2.0
+
+osgi-resource-locator-1.0.1.jar(1.0.1)
+    * License: CDDL
+
+protobuf-java-3.2.0.jar (3.2.0)
+    * License: New BSD license
+
+protobuf-java-util-3.2.0.jar  (3.2.0)
+    * License: New BSD license
+
+swagger-annotations-2.0.8.jar (2.0.8)
+    * License: Apache-2.0
+
+swagger-ui-3.23.0.jar (3.23.0)
+    * License: Apache-2.0
+
+slf4j-api-1.7.25.jar  (1.7.25)
+    * License: MIT license
+    * Licence Path: https://www.slf4j.org/license.html
+    * Project URL: https://github.com/qos-ch/slf4j
+    * Source URL:  https://github.com/qos-ch/slf4j/releases/tag/v_1.7.25
+
+stax2-api-3.1.4.jar (3.1.4)
+    * License: BSD-2-Clause
+
+validation-api-1.1.0.Final.jar (1.1.0.Final)
+  * License: Apache License, 2.0
+
+vavr-0.9.1-sources.jar (0.9.1)
+  * License: Apache License, 2.0
+
+vavr-match-0.9.1.jar (0.9.1)
+  * License: Apache License, 2.0
+
+woodstox-core-asl-4.4.1.jar (4.4.1)
+  * License: Apache License, 2.0
+
+
+FFAMFAMFAM Silk Icon, Version 1.3
+    * License: Creative Commons Attribution 3.0 License
+    * Licence Path: https://creativecommons.org/licenses/by/3.0/
+    * Project: http://www.famfamfam.com/lab/icons/silk/
+    * Source:  http://www.famfamfam.com/lab/icons/silk/
+
+@angular/animations:7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/animations
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/cdk:7.1.1
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api
+    * Source:  https://github.com/angular/angular/releases/tag/7.1.1
+
+
+@angular/common@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io/api/common
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4r
+
+@angular/compiler@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/core@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/forms@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/http@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser-dynamic@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/platform-browser@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+@angular/router@7.2.4
+    * License: MIT
+    * Licence Path: https://github.com/angular/angular/blob/master/LICENSE
+    * Project: https://angular.io
+    * Source:  https://github.com/angular/angular/releases/tag/7.2.4
+
+bootstrap@4.1.3
+    * License: MIT
+    * Licence Path: https://github.com/twbs/bootstrap/raw/master/LICENSE
+    * Project: https://getbootstrap.com/
+    * Source:  https://github.com/twbs/bootstrap
+
+class-transformer@0.1.6
+    * License: MIT
+    * Licence Path: https://github.com/typestack/class-transformer/blob/master/LICENSE
+    * Project: https://github.com/pleerock/class-transformer
+    * Source:  https://github.com/pleerock/class-transformer
+
+core-js@2.6.0
+    * License: MIT
+    * Licence Path: https://github.com/zloirock/core-js/raw/master/LICENSE
+    * Project: https://github.com/zloirock/core-js
+    * Source:  https://github.com/zloirock/core-js/releases/tag/v2.6.0
+
+file-saver@1.3.3
+    * License: MIT
+    * Licence Path: https://github.com/eligrey/FileSaver.js/raw/master/LICENSE.md
+    * Project: https://github.com/eligrey/FileSaver.js
+    * Source:  https://github.com/eligrey/FileSaver.js
+
+font-awesome@4.7.0
+    * License: MIT
+    * Licence Path: https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt
+    * Project: https://fontawesome.com/
+    * Source:  https://github.com/FortAwesome/Font-Awesome
+
+ng2-split-pane@1.3.1
+    * License: MIT
+    * Licence Path: https://github.com/wannabegeek/ng2-split-pane/raw/master/LICENSE
+    * Project: https://github.com/wannabegeek/ng2-split-pane
+    * Source:  https://github.com/wannabegeek/ng2-split-pane
+
+ngx-bootstrap@3.1.2
+    * License: MIT
+    * Licence Path: https://github.com/valor-software/ngx-bootstrap/blob/v3.1.2/LICENSE
+    * Project: https://valor-software.com/ngx-bootstrap
+    * Source:  https://github.com/valor-software/ngx-bootstrap/tree/v3.1.2
+
+@ngx-translate/core@11.0.1
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/core/blob/v11.0.1/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/core
+
+@ngx-translate/http-loader@4.0.0
+    * License: MIT 
+    * Licence Path:   https://github.com/ngx-translate/http-loader/blob/v4.0.0/LICENSE  
+    * Project URL:    http://www.ngx-translate.com/
+    * Source URL:     https://github.com/ngx-translate/http-loader/tree/v4.0.0
+
+primeicons:1.0.0
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeicons/blob/1.0.0/LICENSE
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeicons/tree/1.0.0
+
+primeng@7.0.1
+    * License: MIT
+    * Licence Path: https://github.com/primefaces/primeng/blob/7.0.1/LICENSE.md
+    * Project: https://www.primefaces.org/primeng
+    * Source:  https://github.com/primefaces/primeng/tree/7.0.1
+
+rxjs@6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3
+
+rxjs-compat:6.3.3
+    * License: Apache-2.0
+    * Project: https://rxjs-dev.firebaseapp.com/
+    * Source:  https://github.com/ReactiveX/rxjs/tree/6.3.3/compat
+
+tslib@1.9.0
+    * License: Apache-2.0
+    * Project: https://github.com/Microsoft/tslib
+    * Source:  https://github.com/Microsoft/tslib/tree/1.9.0
+
+zone.js@0.8.26
+    * License: MIT
+    * Licence Path: https://github.com/angular/zone.js/raw/master/LICENSE
+    * Project: https://github.com/angular
+    * Source:  https://github.com/angular/zone.js/releases/tag/v0.8.26
+
+OMG Event Service Specification (1.2)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/EVNT/1.2/
+* Source: https://www.omg.org/spec/EVNT/1.2/pdf
+
+OMG Notification Service Specification (1.1)
+
+* License: LicenseRef - Object-Management-Group-License
+* Project: https://www.omg.org/spec/NOT/
+* Source: https://www.omg.org/spec/NOT/1.1/PDF
+
+ods530.idl
+Date: Hoehenkirchen, 06/01/2016
+"The ASAM Board of Directors releases the IDL files for use under the EPL to the Eclipse IWG openMDM.
+This is valid for all versions of ASAM ODS 5.3.x.
+This permission is valid under the conditions of Eclipse will not modify the file."
+
+AvalonEvent.idl, CorbaFileServer.idl
+Date: 08/15/2016
+"Herewith, we release the generated Client-Source-Code generated from our CORBA IDLs, namely
+* CORBANotification Service (generated from „AvalonEvent.idl”)
+* CORBAFileServer (generated from „CorbaFileServer.idl“),
+Under the Eclipse Public License (EPL). This agreement does not include the „AvalonEvent.idl“ and
+„CorbaFileServer.idl“ itself, which remain protected property of HighQSoft. "
+
+## Cryptography
+
+Content may contain encryption software. The country in which you are currently
+may have restrictions on the import, possession, and use, and/or re-export to
+another country, of encryption software. BEFORE using any encryption software,
+please check the country's laws, regulations and policies concerning the import,
+possession, or use, and re-export of encryption software, to see if this is
+permitted.
diff --git a/org.eclipse.mdm.api.base/build.gradle b/org.eclipse.mdm.api.base/build.gradle
new file mode 100644
index 0000000..60e39f3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/build.gradle
@@ -0,0 +1,48 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+
+description = 'MDM API - Base Model'
+group = 'org.eclipse.mdm'
+version = '5.2.0M1-SNAPSHOT'
+
+apply plugin: 'java'
+apply plugin: 'maven'
+apply plugin: 'eclipse'
+
+repositories {
+    mavenLocal()
+    mavenCentral()
+}
+
+dependencies {
+    // testing
+    testCompile 'junit:junit:4.12'
+    testCompile 'org.mockito:mockito-core:2.13.0' 
+    testCompile 'org.assertj:assertj-core:3.6.2'
+}
+
+jar {
+	metaInf { from 'NOTICE.txt' }
+	metaInf { from 'LICENSE.txt' }
+}
+
+task sourcesJar(type: Jar, dependsOn: classes) {
+	classifier = 'sources'
+	from sourceSets.main.allSource
+}
+
+artifacts {
+	archives sourcesJar
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/gradle.properties b/org.eclipse.mdm.api.base/gradle.properties
new file mode 100644
index 0000000..2ab5436
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradle.properties
@@ -0,0 +1,16 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+ 
+sourceCompatibility=1.8
+targetCompatibility=1.8
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.jar b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..7a3265e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.properties b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82e006
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME

+distributionPath=wrapper/dists

+zipStoreBase=GRADLE_USER_HOME

+zipStorePath=wrapper/dists

+distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip

diff --git a/org.eclipse.mdm.api.base/gradlew b/org.eclipse.mdm.api.base/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/org.eclipse.mdm.api.base/gradlew.bat b/org.eclipse.mdm.api.base/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off

+@rem ##########################################################################

+@rem

+@rem  Gradle startup script for Windows

+@rem

+@rem ##########################################################################

+

+@rem Set local scope for the variables with windows NT shell

+if "%OS%"=="Windows_NT" setlocal

+

+set DIRNAME=%~dp0

+if "%DIRNAME%" == "" set DIRNAME=.

+set APP_BASE_NAME=%~n0

+set APP_HOME=%DIRNAME%

+

+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.

+set DEFAULT_JVM_OPTS=

+

+@rem Find java.exe

+if defined JAVA_HOME goto findJavaFromJavaHome

+

+set JAVA_EXE=java.exe

+%JAVA_EXE% -version >NUL 2>&1

+if "%ERRORLEVEL%" == "0" goto init

+

+echo.

+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:findJavaFromJavaHome

+set JAVA_HOME=%JAVA_HOME:"=%

+set JAVA_EXE=%JAVA_HOME%/bin/java.exe

+

+if exist "%JAVA_EXE%" goto init

+

+echo.

+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%

+echo.

+echo Please set the JAVA_HOME variable in your environment to match the

+echo location of your Java installation.

+

+goto fail

+

+:init

+@rem Get command-line arguments, handling Windows variants

+

+if not "%OS%" == "Windows_NT" goto win9xME_args

+

+:win9xME_args

+@rem Slurp the command line arguments.

+set CMD_LINE_ARGS=

+set _SKIP=2

+

+:win9xME_args_slurp

+if "x%~1" == "x" goto execute

+

+set CMD_LINE_ARGS=%*

+

+:execute

+@rem Setup the command line

+

+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

+

+@rem Execute Gradle

+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

+

+:end

+@rem End local scope for the variables with windows NT shell

+if "%ERRORLEVEL%"=="0" goto mainEnd

+

+:fail

+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of

+rem the _cmd.exe /c_ return code!

+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1

+exit /b 1

+

+:mainEnd

+if "%OS%"=="Windows_NT" endlocal

+

+:omega

diff --git a/org.eclipse.mdm.api.base/settings.gradle b/org.eclipse.mdm.api.base/settings.gradle
new file mode 100644
index 0000000..8e8ce19
--- /dev/null
+++ b/org.eclipse.mdm.api.base/settings.gradle
@@ -0,0 +1,15 @@
+/********************************************************************************
+ * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+rootProject.name = 'org.eclipse.mdm.api.base'
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContext.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContext.java
new file mode 100644
index 0000000..d3a3976
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContext.java
@@ -0,0 +1,130 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.ModelManager;
+import org.eclipse.mdm.api.base.file.FileService;
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+import org.eclipse.mdm.api.base.notification.NotificationService;
+import org.eclipse.mdm.api.base.query.QueryService;
+import org.eclipse.mdm.api.base.search.SearchService;
+
+/**
+ * Base application context represents a connection/session to the underlying
+ * data store. It provides access to managers and services.
+ *
+ * @param <S> Type of the connected entity factory.
+ * @param <T> Type of the connected entity manager.
+ * @since 1.0.0
+ */
+public interface BaseApplicationContext<S extends BaseEntityFactory, T extends BaseEntityManager>
+		extends AutoCloseable {
+	/**
+	 * The returned service loads entities from the underlying data source.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 */
+	default Optional<T> getEntityManager() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service creates new entities.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 */
+	default Optional<S> getEntityFactory() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service provides access to the application model's meta data.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see ModelManager
+	 */
+	default Optional<ModelManager> getModelManager() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service provides advanced search capabilities for supported
+	 * entity types.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see SearchService
+	 */
+	default Optional<SearchService> getSearchService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service provides access to the low level query API.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see QueryService
+	 */
+	default Optional<QueryService> getQueryService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service allows to download linked files from the file storage.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see FileService
+	 */
+	default Optional<FileService> getFileService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * The returned service allows to register/unregister for events at a
+	 * registration service.
+	 *
+	 * @return {@code Optional} is empty if no such service is available.
+	 * @see NotificationService
+	 */
+	default Optional<NotificationService> getNotificationService() {
+		return Optional.empty();
+	}
+
+	/**
+	 * Returns a map with all configuration parameters, which where given to
+	 * initialize this context.
+	 * 
+	 * @return map with configuration parameters
+	 */
+	Map<String, String> getParameters();
+
+	/**
+	 * Returns a string describing the type of the underlying API implementation.
+	 * The exact content is up to the individual adapter and it is intended to be
+	 * interpreted by the client.
+	 * 
+	 * @return a string describing the type of the underlying API implementation.
+	 */
+	String getAdapterType();
+
+	/**
+	 * Closes the BaseContext.
+	 * 
+	 * This closes all underlying managers and services.
+	 */
+	void close() throws ConnectionException;
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContextFactory.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContextFactory.java
new file mode 100644
index 0000000..eab20c5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseApplicationContextFactory.java
@@ -0,0 +1,39 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+
+/**
+ * Takes connection parameters and produces a corresponding base application
+ * context.
+ *
+ * @param <T> Type of the connected entity manager.
+ * @since 1.0.0
+ */
+public interface BaseApplicationContextFactory<T extends BaseApplicationContext<? extends BaseEntityFactory, ? extends BaseEntityManager>> {
+
+	/**
+	 * Takes given connection parameters and creates a new context, which is
+	 * permanently connected with configured data source.
+	 *
+	 * @param connectionParameters The connection parameters.
+	 * @return The connected context is returned.
+	 * @throws ConnectionException Thrown if unable to connect to a data source.
+	 */
+	T connect(Map<String, String> connectionParameters) throws ConnectionException;
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseEntityManager.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseEntityManager.java
new file mode 100644
index 0000000..cf656d9
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/BaseEntityManager.java
@@ -0,0 +1,285 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.massdata.ReadRequest;
+import org.eclipse.mdm.api.base.model.ContextDescribable;
+import org.eclipse.mdm.api.base.model.ContextRoot;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Environment;
+import org.eclipse.mdm.api.base.model.MeasuredValues;
+import org.eclipse.mdm.api.base.model.Measurement;
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.model.User;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Provides business layer CRUD operations and services (CREATE, READ, UPDATE,
+ * INSERT).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface BaseEntityManager {
+
+	/**
+	 * Returns the {@link Environment} this entity manager is connected to.
+	 *
+	 * @return The {@code Environment} is returned.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code
+	 * 		Environment}        .
+	 */
+	Environment loadEnvironment() throws DataAccessException;
+
+	/**
+	 * Returns the {@link User} which was used to connect to the underlying data
+	 * source.
+	 *
+	 * @return {@code Optional} is empty if the data source connection is user
+	 *         independent, which is implementation specific.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code User}.
+	 */
+	default Optional<User> loadLoggedOnUser() throws DataAccessException {
+		return Optional.empty();
+	}
+
+	/**
+	 * Loads the entity identified by given entity class and its instance ID.
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entity.
+	 * @param instanceID  The instance ID.
+	 * @return The entity with given instance ID is returned.
+	 * @throws DataAccessException Thrown if unable to retrieve the entity.
+	 */
+	default <T extends Entity> T load(Class<T> entityClass, String instanceID) throws DataAccessException {
+		List<T> entities = load(entityClass, Collections.singletonList(instanceID));
+		if (entities.size() != 1) {
+			throw new DataAccessException("Failed to load entity by instance ID.");
+		}
+		return entities.get(0);
+	}
+
+	/**
+	 * Loads the entities identified by given entity class and its instance IDs.
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @param instanceIDs The instance IDs to load. If a instance ID does not exist,
+	 *                    it is ignored.
+	 * @return Entities are returned in a list.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 */
+	<T extends Entity> List<T> load(Class<T> entityClass, Collection<String> instanceIDs) throws DataAccessException;
+
+	/**
+	 * Loads all available entities of given type. This method is useful while
+	 * working with types whose amount is known to be fairly small (e.g.:
+	 * {@code Unit}, {@code Quantity}, etc.). If a type is given where thousand
+	 * instances exist (e.g.: {@code Test}) the behavior of this method is
+	 * implementation specific. The following invocation might take its time to
+	 * complete or even result in an exception as soon as too many results are
+	 * found:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	List<Test> tests = entityManager.loadAll(Test.class);
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @return Entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 * @see #loadAll(Class, String)
+	 */
+	default <T extends Entity> List<T> loadAll(Class<T> entityClass) throws DataAccessException {
+		return loadAll(entityClass, "*");
+	}
+
+	/**
+	 * Loads all available entities of given type whose name fulfills the given
+	 * pattern. This method is useful while working with types whose amount is known
+	 * to be fairly small (e.g.: {@code Unit}, {@code Quantity}, etc.). If a type is
+	 * given where thousand instances exist (e.g.: {@code Test}) the behavior of
+	 * this method is implementation specific. The following invocation might take
+	 * its time to complete or even result in an exception as soon as too many
+	 * results are found:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	// retrieve all tests whose name starts with 'Example'
+	 * 	List<Test> tests = entityManager.loadAll(Test.class, "Example*");
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired type.
+	 * @param entityClass Type of the returned entities.
+	 * @param pattern     Is always case sensitive and may contain wildcard
+	 *                    characters as follows: "?" for one matching character and
+	 *                    "*" for a sequence of matching characters.
+	 * @return Matched entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the entities.
+	 * @see #loadAll(Class)
+	 */
+	<T extends Entity> List<T> loadAll(Class<T> entityClass, String pattern) throws DataAccessException;
+
+	/**
+	 * Loads the parent entity for given child. Each modeled entity provides public
+	 * fields for available parent entity types e.g.:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	Optional<Test> parentTest = entityManager.loadParent(testStep, TestStep.PARENT_TYPE_TEST);
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired parent type.
+	 * @param child       The child entity.
+	 * @param entityClass The desired parent entity type.
+	 * @return {@code Optional} is empty if parent entity could not be found.
+	 * @throws DataAccessException Thrown if unable to retrieve parent entity.
+	 */
+	<T extends Entity> Optional<T> loadParent(Entity child, Class<T> entityClass) throws DataAccessException;
+
+	/**
+	 * Loads all related children of given type for given parent entity. Each
+	 * modeled entity provides public fields for available child entity types e.g.:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	List<Channel> channels = entityManager.loadChildren(measurement, Measurement.CHILD_TYPE_CHANNEL);
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired child type.
+	 * @param parent      The parent entity.
+	 * @param entityClass The desired child entity type.
+	 * @return Related child entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the children.
+	 * @see #loadChildren(Entity, Class, String)
+	 */
+	default <T extends Entity> List<T> loadChildren(Entity parent, Class<T> entityClass) throws DataAccessException {
+		return loadChildren(parent, entityClass, "*");
+	}
+
+	/**
+	 * Loads all related children of given type for given parent entity whose name
+	 * fulfills the given pattern. Each modeled entity provides public fields for
+	 * available child entity types e.g.:
+	 *
+	 * <pre>
+	 * {
+	 * 	&#64;code
+	 * 	List<TestStep> testSteps = entityManager.loadChildren(test, Test.CHILD_TYPE_TESTSTEP, "Example*");
+	 * }
+	 * </pre>
+	 *
+	 * @param <T>         The desired child type.
+	 * @param parent      The parent entity.
+	 * @param entityClass The desired child entity type.
+	 * @param pattern     Is always case sensitive and may contain wildcard
+	 *                    characters as follows: "?" for one matching character and
+	 *                    "*" for a sequence of matching characters.
+	 * @return Matched child entities are returned in a {@code List}.
+	 * @throws DataAccessException Thrown if unable to retrieve the children.
+	 * @see #loadChildren(Entity, Class)
+	 */
+	<T extends Entity> List<T> loadChildren(Entity parent, Class<T> entityClass, String pattern)
+			throws DataAccessException;
+
+	/**
+	 * Queries available {@link ContextType} for given {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or a {@link Measurement}
+	 * @return {@code List} contains the {@code ContextType} of each referenced
+	 *         {@link ContextRoot}.
+	 * @throws DataAccessException Thrown if unable to query the available
+	 *                             {@code ContextType}s.
+	 */
+	List<ContextType> loadContextTypes(ContextDescribable contextDescribable) throws DataAccessException;
+
+	/**
+	 * Loads the requested {@link ContextRoot}s for given
+	 * {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or {@link Measurement}.
+	 * @param contextTypes       The requested context types. If omitted, all types
+	 *                           are be loaded.
+	 * @return The ordered contexts for given {@code TestStep} or the measured ones
+	 *         for {@code Measurement} are returned in a {@code Map}.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code
+	 * 		ContextRoot}        s.
+	 * @see ContextType
+	 */
+	Map<ContextType, ContextRoot> loadContexts(ContextDescribable contextDescribable, ContextType... contextTypes)
+			throws DataAccessException;
+
+	/**
+	 * @param entity       The entity
+	 * @param relationName The name of the relation, which entities should be
+	 *                     loaded.
+	 * @param relatedClass Class of the related entities.
+	 * @return The related entities for the given {@link Entity} and relationName
+	 */
+	<T extends Entity> List<T> loadRelatedEntities(Entity entity, String relationName, Class<T> relatedClass);
+
+	/**
+	 * Retrieves the {@link MeasuredValues} as specified by the given
+	 * {@link ReadRequest}.
+	 *
+	 * @param readRequest Provides all required informations to process the request.
+	 * @return Returns the {@code MeasuredValues} in a {@code List} as specified in
+	 *         the given {@code ReadRequest}.
+	 * @throws DataAccessException Thrown if unable to access the measured values.
+	 */
+	List<MeasuredValues> readMeasuredValues(ReadRequest readRequest) throws DataAccessException;
+
+	/**
+	 * Creates a new {@link Transaction} for modifying access.
+	 *
+	 * @return A new {@code Transaction} is returned.
+	 * @throws DataAccessException Thrown if unable to create a new
+	 *                             {@code Transaction}.
+	 */
+	Transaction startTransaction() throws DataAccessException;
+
+	/**
+	 * Returns links to the given entities in the data store. The format of the
+	 * links is adapter specific and depends on the underlying data store. The links
+	 * can be used by the client to directly access the entities by bypassing the
+	 * MDM API, if the client is capable of accessing the adapters data store. The
+	 * client can invoke {@link BaseApplicationContext#getAdapterType()} to get the
+	 * type of the adapter.
+	 * 
+	 * @param entities the Entities for which the links are retrieved
+	 * @return the links to the given entities in the data store abstracted by the
+	 *         current adapter. The map contains the requested entities as keys and
+	 *         the corresponding links as values.
+	 */
+	Map<Entity, String> getLinks(Collection<Entity> entities);
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ConnectionException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ConnectionException.java
new file mode 100644
index 0000000..0d71120
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ConnectionException.java
@@ -0,0 +1,54 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+/**
+ * Thrown to indicate (dis-)connect errors with a data source.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class ConnectionException extends Exception {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final long serialVersionUID = -1299685705186484972L;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The error message.
+	 */
+	public ConnectionException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message   The error message.
+	 * @param throwable The origin cause.
+	 */
+	public ConnectionException(String message, Throwable throwable) {
+		super(message, throwable);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ServiceNotProvidedException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ServiceNotProvidedException.java
new file mode 100644
index 0000000..1a4b5e3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/ServiceNotProvidedException.java
@@ -0,0 +1,32 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+/**
+ * This exception indicates that a service is not provided by an adapter.
+ */
+public class ServiceNotProvidedException extends RuntimeException {
+
+	private static final long serialVersionUID = -4829618036958929415L;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param clazz the service that is not provided
+	 */
+	public ServiceNotProvidedException(Class<?> clazz) {
+		super("The service '" + clazz + "' is not implemented!");
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/Transaction.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/Transaction.java
new file mode 100644
index 0000000..10b78fb
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/Transaction.java
@@ -0,0 +1,94 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Collection;
+
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.model.Deletable;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.MeasuredValues;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Provides business layer write operations (CREATE, UPDATE, DELETE).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface Transaction {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	// TODO: it should be possible to a attach a listener
+	// -> progress notification updates while uploading files
+	// -> any other useful informations?!
+
+	/**
+	 * Persists given entities and implicitly updates their instance IDs.
+	 *
+	 * @param <T>      Most common type of the given entities.
+	 * @param entities Entities that will be persisted.
+	 * @throws DataAccessException Thrown in case of errors while writing entities.
+	 */
+	<T extends Entity> void create(Collection<T> entities) throws DataAccessException;
+
+	/**
+	 * Updates given entities.
+	 *
+	 * @param <T>      Most common type of the given entities.
+	 * @param entities Entities that will be updated.
+	 * @throws DataAccessException Thrown in case of errors while writing entities.
+	 */
+	<T extends Entity> void update(Collection<T> entities) throws DataAccessException;
+
+	/**
+	 * Deletes given entities. Related children will be searched and automatically
+	 * removed.
+	 *
+	 * @param <T>      Most common type of the given entities.
+	 * @param entities Entities that will be deleted (including their children).
+	 * @throws DataAccessException Thrown in case of errors while deleting entities.
+	 */
+	<T extends Deletable> void delete(Collection<T> entities) throws DataAccessException;
+
+	/**
+	 * Creates {@link MeasuredValues} as specified by the given
+	 * {@link WriteRequest}s.
+	 *
+	 * @param writeRequests Provides all required informations to process the
+	 *                      request.
+	 * @throws DataAccessException Thrown if unable to create specified measured
+	 *                             values.
+	 */
+	void writeMeasuredValues(Collection<WriteRequest> writeRequests) throws DataAccessException;
+
+	/**
+	 * Commit this transaction. Any changes made within this transaction become
+	 * permanent.
+	 *
+	 * @throws DataAccessException Thrown if unable to commit this transaction.
+	 */
+	void commit() throws DataAccessException;
+
+	/**
+	 * Aborts (rollback) this transaction. Any changes made within this transaction
+	 * will be lost.
+	 */
+	void abort();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Attribute.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Attribute.java
new file mode 100644
index 0000000..206829a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Attribute.java
@@ -0,0 +1,171 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.lang.reflect.Field;
+
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Represents a modeled attribute.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see ValueType
+ * @see Value
+ */
+public interface Attribute {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link EntityType} this attribute belongs to.
+	 *
+	 * @return The owning {@code EntityType} is returned.
+	 */
+	EntityType getEntityType();
+
+	/**
+	 * Returns the name of this attribute.
+	 *
+	 * @return The name is returned.
+	 */
+	String getName();
+
+	/**
+	 * Returns the unit name of this attribute.
+	 *
+	 * @return The unit name is returned.
+	 */
+	String getUnit();
+
+	/**
+	 * Returns the {@link ValueType} of this attribute.
+	 *
+	 * @return The {@code ValueType} is returned.
+	 */
+	ValueType getValueType();
+
+	/**
+	 * Returns the enumeration {@code Class} associated with this {@code Attribute}.
+	 *
+	 * @return The enumeration {@code Class} associated with this {@code Attribute}
+	 *         is returned.
+	 * @throws IllegalStateException Thrown if the {@link ValueType} of this
+	 *                               {@code Attribute} is neither
+	 *                               {@link ValueType#ENUMERATION} nor
+	 *                               {@link ValueType#ENUMERATION_SEQUENCE}.
+	 */
+	Enumeration<?> getEnumObj();
+
+	/**
+	 * Creates a new and empty {@link Value}.
+	 *
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue() {
+		ValueType valueType = getValueType();
+		if (valueType.isEnumerationType()) {
+			return valueType.create(getEnumObj(), getName());
+		} else {
+			return valueType.create(getName());
+		}
+	}
+
+	/**
+	 * Creates a new {@link Value} with given initial value.
+	 *
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue(Object input) {
+		return createValue("", input);
+	}
+
+	/**
+	 * Creates a new {@link Value} with given unit name and initial value.
+	 *
+	 * @param unit  The name of unit.
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue(String unit, Object input) {
+		return createValue(unit, true, input);
+	}
+
+	/**
+	 * Creates a new sequence {@link Value} with given unit name and initial value.
+	 *
+	 * @param unit  The name of unit.
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValueSeq(String unit, Object input) {
+		if (getValueType().isEnumerationType()) {
+			return createEnumerationSequence(unit, input);
+		}
+		return createValueSequence(unit, input);
+	}
+
+	default Value createValueSequence(String unit, Object input) {
+		ValueType valueType = getValueType();
+		try {
+			Field field = valueType.getClass().getField(valueType.name() + "_SEQUENCE");
+			ValueType<?> sequenceValueType = (ValueType<?>) field.get(valueType);
+			return sequenceValueType.create(getName(), unit, true, input);
+
+		} catch (NoSuchFieldException | ClassCastException | IllegalAccessException e) {
+			throw new RuntimeException("Can't figure out sequence type for " + valueType.name());
+		}
+	}
+
+	default Value createEnumerationSequence(String unit, Object input) {
+		ValueType valueType = getValueType().toSequenceType();
+		return valueType.create(getName(), unit, true, input, getEnumObj().getName());
+	}
+
+	/**
+	 * Creates a new {@link Value} with given unit name, initial valid flag and
+	 * value.
+	 *
+	 * @param unit  The name of unit.
+	 * @param valid The initial valid flag.
+	 * @param input The initial value.
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue(String unit, boolean valid, Object input) {
+		ValueType<?> valueType = getValueType();
+		if (valueType.isEnumerationType()) {
+			return valueType.create(getName(), unit, valid, input, getEnumObj().getName());
+		} else {
+			return valueType.create(getName(), unit, valid, input);
+		}
+	}
+
+	/**
+	 * Returns the name of this attribute.
+	 *
+	 * @return The name of this attribute is returned.
+	 */
+	@Override
+	String toString();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ChildrenStore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ChildrenStore.java
new file mode 100644
index 0000000..b02a638
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ChildrenStore.java
@@ -0,0 +1,110 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.Deletable;
+
+/**
+ * Holds related entities of any kind and keeps track of modifications.
+ */
+public final class ChildrenStore {
+
+	private final Map<Class<? extends Deletable>, List<? extends Deletable>> current = new HashMap<>(0);
+	private final Map<Class<? extends Deletable>, List<? extends Deletable>> removed = new HashMap<>(0);
+
+	/**
+	 * Returns current set of related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<Class<? extends Deletable>, List<? extends Deletable>> getCurrent() {
+		return Collections.unmodifiableMap(current);
+	}
+
+	/**
+	 * Returns current set of removed related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<Class<? extends Deletable>, List<? extends Deletable>> getRemoved() {
+		return Collections.unmodifiableMap(removed);
+	}
+
+	/**
+	 * Returns related child entities of given type.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @return Returned {@code List} is unmodifiable.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> List<T> get(Class<T> entityClass) {
+		return Collections.unmodifiableList((List<T>) current.computeIfAbsent(entityClass, k -> new ArrayList<>()));
+	}
+
+	/**
+	 * Sorts the child entities with given {@code Comparator}.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @param comparator  Used for sorting.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> void sort(Class<T> entityClass, Comparator<? super T> comparator) {
+		List<T> children = (List<T>) current.get(entityClass);
+		if (children != null) {
+			children.sort(comparator);
+		}
+	}
+
+	/**
+	 * Adds given child entity.
+	 *
+	 * @param child The new child.
+	 */
+	@SuppressWarnings("unchecked")
+	public void add(Deletable child) {
+		removed.getOrDefault(child.getClass(), new ArrayList<>()).remove(child);
+		((List<Deletable>) current.computeIfAbsent(child.getClass(), k -> new ArrayList<>())).add(child);
+	}
+
+	/**
+	 * Removes given child entity.
+	 *
+	 * @param child The child which will be removed.
+	 */
+	@SuppressWarnings("unchecked")
+	public void remove(Deletable child) {
+		List<Deletable> children = (List<Deletable>) current.getOrDefault(child.getClass(), new ArrayList<>());
+		if (children.remove(child) && child.getID() != null && child.getID().length() > 0) {
+			((List<Deletable>) removed.computeIfAbsent(child.getClass(), k -> new ArrayList<>())).add(child);
+		}
+	}
+
+	/**
+	 * Clean up list of removed entities.
+	 */
+	void apply() {
+		removed.clear();
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Core.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Core.java
new file mode 100644
index 0000000..33a71d0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Core.java
@@ -0,0 +1,202 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Provides access to the internals of any entity:
+ *
+ * <ul>
+ * <li>name of the data source</li>
+ * <li>name of the type</li>
+ * <li>instance ID</li>
+ * <li>values</li>
+ * <li>added/removed file links</li>
+ * <li>related entities</li>
+ * <li>parent/child entities</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface Core {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of the data source this entity was retrieved from.
+	 *
+	 * @return Name of the data source.
+	 */
+	String getSourceName();
+
+	/**
+	 * Returns the name of the entity type.
+	 *
+	 * @return Name of the entity type is returned.
+	 */
+	String getTypeName();
+
+	/**
+	 * Returns the instance ID or {@code 0} if this instance is not yet persisted.
+	 *
+	 * @return The instance ID is returned.
+	 */
+	String getID();
+
+	/**
+	 * Sets an instance ID.
+	 *
+	 * @param instanceID The new instance ID.
+	 */
+	void setID(String instanceID);
+
+	/**
+	 * Returns <i>all</i> {@link Value} containers of this entity.
+	 *
+	 * @return Values mapped by their name are returned.
+	 */
+	Map<String, Value> getValues();
+
+	/**
+	 * Hides {@link Value} containers whose name is contained in the given names
+	 * {@code Collection}. E.g. hide attributes from a CatalogComponent when not
+	 * used in a TemplateComponent.
+	 *
+	 * @param names Names of the {@code Value} which shall be hidden.
+	 */
+	void hideValues(Collection<String> names);
+
+	/**
+	 * Returns <i>all</i> {@link Value} containers, including the hidden ones.
+	 *
+	 * @return All {@code Value} containers are returned.
+	 */
+	Map<String, Value> getAllValues();
+
+	/**
+	 * Returns all newly added {@link FileLink}.
+	 *
+	 * @return New {@code FileLink}s are returned.
+	 */
+	default List<FileLink> getAddedFileLinks() {
+		Predicate<FileLink> isRemote = FileLink::isRemote;
+
+		List<FileLink> fileLinks = getValues().values().stream().filter(v -> v.getValueType().isFileLink())
+				.filter(Value::isValid).map(v -> (FileLink) v.extract()).filter(isRemote.negate())
+				.collect(Collectors.toList());
+
+		List<Value> values = getValues().values().stream().filter(v -> v.getValueType().isFileLinkSequence())
+				.filter(Value::isValid).collect(Collectors.toList());
+
+		for (Value value : values) {
+			Arrays.stream((FileLink[]) value.extract()).filter(isRemote.negate()).forEach(fileLinks::add);
+		}
+
+		return fileLinks;
+	}
+
+	/**
+	 * Returns all removed {@link FileLink}s.
+	 *
+	 * @return Removed {@code FileLink}s are returned.
+	 */
+	default List<FileLink> getRemovedFileLinks() {
+		Predicate<FileLink> isRemote = FileLink::isRemote;
+
+		List<FileLink> fileLinks = getValues().values().stream().filter(v -> v.getValueType().isFileLink())
+				.filter(Value::isModified).map(v -> (FileLink) v.extractInitial()).filter(Objects::nonNull)
+				.filter(isRemote).collect(Collectors.toList());
+
+		List<Value> values = getValues().values().stream().filter(v -> v.getValueType().isFileLinkSequence())
+				.filter(Value::wasValid).filter(Value::isModified).collect(Collectors.toList());
+
+		for (Value value : values) {
+			List<FileLink> current = Arrays.asList((FileLink[]) value.extract());
+			Arrays.stream((FileLink[]) value.extractInitial()).filter(fl -> !current.contains(fl))
+					.forEach(fileLinks::add);
+		}
+
+		return fileLinks;
+	}
+
+	/**
+	 * Applies modifications made to the entity stores and {@link Value} containers.
+	 * This method is called when a transaction is finalized (all operations
+	 * completed successfully) to reflect the new state in the core.
+	 */
+	default void apply() {
+		// apply the removed state to mutable entities
+		getMutableStore().apply();
+
+		// apply the removed state to children
+		getChildrenStore().apply();
+
+		// apply modified values
+		getValues().values().stream().filter(Value::isModified).forEach(Value::apply);
+	}
+
+	/**
+	 * Returns the mutable {@link EntityStore}. Holds entities with mutable
+	 * (editable) relations to the entity bound to this core instance. This store
+	 * only contains always only one relation for one entity. For child relations
+	 * use {@link ChildrenStore}.
+	 *
+	 * @return The mutable {@code EntityStore} is returned.
+	 */
+	EntityStore getMutableStore();
+
+	/**
+	 * Returns the permanent {@link EntityStore}. Holds entities with immutable
+	 * (non-editable) relations to the entity bound to this core instance. E.g.
+	 * relations to the parent entity.
+	 *
+	 * @return The permanent {@code EntityStore} is returned.
+	 */
+	EntityStore getPermanentStore();
+
+	/**
+	 * Returns the {@link ChildrenStore}. This store holds child entities with
+	 * relations to the entity bound to this core instance.
+	 * 
+	 * @return The {@code ChildrenStore} is returned.
+	 */
+	// TODO (8.11.2017; Florian Schmitt, Angelika Wittek)
+	// Entities with more than one related entity that do not refer to children,
+	// have also to go here,
+	// as it is not permitted to go to the other stores. Does this work at all?
+	ChildrenStore getChildrenStore();
+
+	/**
+	 * Returns the {@link RelationStore}. This store holds related entities for N to
+	 * M relations.
+	 * 
+	 * @return The {@link RelationStore} is returned
+	 */
+	RelationStore getNtoMStore();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/DefaultCore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/DefaultCore.java
new file mode 100644
index 0000000..d66d41c
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/DefaultCore.java
@@ -0,0 +1,203 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.Record;
+
+/**
+ * Provides access to the internals of any entity:
+ *
+ * <ul>
+ * <li>name of the data source</li>
+ * <li>name of the type</li>
+ * <li>instance ID</li>
+ * <li>values</li>
+ * <li>added/removed file links</li>
+ * <li>related entities</li>
+ * <li>parent/child entities</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public class DefaultCore implements Core {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final EntityStore permanentEntityStorage = new EntityStore();
+	private final EntityStore mutableEntityStorage = new EntityStore();
+	private final ChildrenStore childrenStore = new ChildrenStore();
+	private final RelationStore ntoMStore = new RelationStore();
+
+	private final Map<String, Value> values = new HashMap<>();
+	private final Map<String, Value> hiddenValues = new HashMap<>();
+
+	private final String sourceName;
+	private final String typeName;
+
+	private String instanceID;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructs a new {@link Core} initialized with a queried {@link Record}.
+	 *
+	 * @param record The queried {@code Record}.
+	 */
+	public DefaultCore(Record record) {
+		setID(record.getID());
+		values.putAll(record.getValues());
+		values.remove(Entity.ATTR_ID);
+
+		// remove any contained relation attributes
+		EntityType entityType = record.getEntityType();
+		entityType.getRelations().stream().map(Relation::getName).forEach(values::remove);
+
+		sourceName = entityType.getSourceName();
+		typeName = entityType.getName();
+	}
+
+	/**
+	 * Constructs a new empty {@link Core}. The ID is set to an empty String.
+	 *
+	 * @param entityType The associated {@link EntityType}.
+	 */
+	public DefaultCore(EntityType entityType) {
+		setID("");
+		values.putAll(entityType.createValues());
+		values.remove(Entity.ATTR_ID);
+
+		sourceName = entityType.getSourceName();
+		typeName = entityType.getName();
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getSourceName() {
+		return sourceName;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getTypeName() {
+		return typeName;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getID() {
+		return instanceID;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void setID(String instanceID) {
+		this.instanceID = instanceID;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<String, Value> getValues() {
+		return values;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public void hideValues(Collection<String> names) {
+		if (names.isEmpty()) {
+			return;
+		}
+
+		for (String name : names) {
+			Value value = values.remove(name);
+			if (name != null) {
+				hiddenValues.put(name, value);
+			}
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<String, Value> getAllValues() {
+		if (hiddenValues.isEmpty()) {
+			return values;
+		}
+
+		Map<String, Value> allValues = new HashMap<>(values);
+		allValues.putAll(hiddenValues);
+		return allValues;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityStore getMutableStore() {
+		return mutableEntityStorage;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public EntityStore getPermanentStore() {
+		return permanentEntityStorage;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public ChildrenStore getChildrenStore() {
+		return childrenStore;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public RelationStore getNtoMStore() {
+		return ntoMStore;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityStore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityStore.java
new file mode 100644
index 0000000..129ee3d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityStore.java
@@ -0,0 +1,178 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+
+/**
+ * Holds related entities of any kind and keeps track of modifications.
+ */
+public final class EntityStore {
+
+	private final Map<String, Entity> current = new HashMap<>(0);
+	private final Map<String, Entity> removed = new HashMap<>(0);
+
+	/**
+	 * Returns current set of related entities.
+	 *
+	 * @return Returned {@code Collection} is unmodifiable.
+	 */
+	public Collection<Entity> getCurrent() {
+		return Collections.unmodifiableCollection(current.values());
+	}
+
+	/**
+	 * Returns current set of removed related entities.
+	 *
+	 * @return Returned {@code Collection} is unmodifiable.
+	 */
+	public Collection<Entity> getRemoved() {
+		return Collections.unmodifiableCollection(removed.values());
+	}
+
+	/**
+	 * Returns related entity identified by given entity class.
+	 *
+	 * @param <T>         The desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @return The related entity is returned or null of not defined.
+	 */
+	public <T extends Entity> T get(Class<T> entityClass) {
+		return get(entityClass.getSimpleName(), entityClass);
+	}
+
+	/**
+	 * Returns related entity identified by given entity class.
+	 *
+	 * @param <T>          The desired entity type.
+	 * @param relationName The relation name the entity is referenced by.
+	 * @param entityClass  Used as identifier.
+	 * @return The related entity is returned or null of not defined.
+	 */
+	public <T extends Entity> T get(String relationName, Class<T> entityClass) {
+		return entityClass.cast(current.get(relationName));
+	}
+
+	/**
+	 * Replaces a related entity with the given one.
+	 *
+	 * @param entity The new related entity.
+	 */
+	public void set(Entity entity) {
+		set(entity.getClass().getSimpleName(), entity);
+	}
+
+	/**
+	 * Replaces a related entity with the given one.
+	 *
+	 * @param name   The name of the relation the entity is referenced by.
+	 * @param entity The new related entity.
+	 */
+	public void set(String name, Entity entity) {
+		Entity old = current.put(name, entity);
+		if (old != null) {
+			removed.put(name, old);
+		}
+	}
+
+	/**
+	 * Removes a related entity for given entity class.
+	 *
+	 * @param entityClass Used as identifier.
+	 */
+	public void remove(Class<? extends Entity> entityClass) {
+		String key = entityClass.getSimpleName();
+		remove(key, entityClass);
+	}
+
+	/**
+	 * Removes a related entity for given relation name and entity class.
+	 *
+	 * @param name        The name of the relation the entity is referenced by.
+	 * @param entityClass Used as identifier.
+	 */
+	public void remove(String name, Class<? extends Entity> entityClass) {
+		Entity old = current.remove(name);
+		if (old != null) {
+			removed.put(name, old);
+		}
+	}
+
+	/**
+	 * Returns related entity identified by given entity class and
+	 * {@link ContextType}.
+	 *
+	 * @param <T>         The desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @param contextType Used as identifier.
+	 * @return The related entity is returned or null of not defined.
+	 */
+	public <T extends Entity> T get(Class<T> entityClass, ContextType contextType) {
+		return entityClass.cast(current.get(createContextTypeKey(entityClass, contextType)));
+	}
+
+	/**
+	 * Replaces a related entity with the given one.
+	 *
+	 * @param entity      The new related entity.
+	 * @param contextType Used as identifier.
+	 */
+	public void set(Entity entity, ContextType contextType) {
+		String key = createContextTypeKey(entity.getClass(), contextType);
+		Entity old = current.put(key, entity);
+		if (old != null) {
+			removed.put(key, old);
+		}
+	}
+
+	/**
+	 * Removes a related entity for given entity class and {@link ContextType}.
+	 *
+	 * @param entityClass Used as identifier.
+	 * @param contextType Used as identifier.
+	 */
+	public void remove(Class<? extends Entity> entityClass, ContextType contextType) {
+		String key = createContextTypeKey(entityClass, contextType);
+		Entity old = current.remove(key);
+		if (old != null) {
+			removed.put(key, old);
+		}
+	}
+
+	/**
+	 * Clean up list of removed entities.
+	 */
+	void apply() {
+		removed.clear();
+	}
+
+	/**
+	 * Generates a key from given entity class and {@link ContextType}.
+	 *
+	 * @param entityClass Identifier part 1.
+	 * @param contextType Identifier part 2.
+	 * @return A context type dependent key is returned.
+	 */
+	private static String createContextTypeKey(Class<? extends Entity> entityClass, ContextType contextType) {
+		return entityClass.getSimpleName() + '_' + contextType;
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityType.java
new file mode 100644
index 0000000..d4567eb
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/EntityType.java
@@ -0,0 +1,196 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Represents a modeled entity type.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Attribute
+ * @see Relation
+ * @see RelationType
+ */
+public interface EntityType {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of the data source.
+	 *
+	 * @return Name of the data source is returned.
+	 */
+	String getSourceName();
+
+	/**
+	 * Returns the name of this entity type.
+	 *
+	 * @return The name is returned.
+	 */
+	String getName();
+
+	/**
+	 * Returns the ID of this entity type.
+	 *
+	 * @return The ID is returned.
+	 */
+	String getId();
+
+	/**
+	 * Returns all {@link Attribute}s of this entity type.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> Relation attributes are <i>not</i> part of the returned
+	 * {@code List}.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Attribute> getAttributes();
+
+	/**
+	 * Returns the ID {@link Attribute} of this entity type.
+	 *
+	 * @return The ID {@code Attribute} is returned.
+	 * @see Entity#ATTR_ID
+	 */
+	default Attribute getIDAttribute() {
+		return getAttribute(Entity.ATTR_ID);
+	}
+
+	/**
+	 * Returns the name {@link Attribute} of this entity type.
+	 *
+	 * @return The name {@code Attribute} is returned.
+	 * @see Entity#ATTR_NAME
+	 */
+	default Attribute getNameAttribute() {
+		return getAttribute(Entity.ATTR_NAME);
+	}
+
+	/**
+	 * Returns the mime type {@link Attribute} for this entity type.
+	 *
+	 * @return The mime type {@code Attribute} is returned.
+	 * @see Entity#ATTR_MIMETYPE
+	 */
+	default Attribute getMimeTypeAttribute() {
+		return getAttribute(Entity.ATTR_MIMETYPE);
+	}
+
+	/**
+	 * Returns either the {@link Attribute} identified by the given name or the
+	 * corresponding relation {@code Attribute} (foreign key) as returned by
+	 * {@link Relation#getAttribute()}.
+	 *
+	 * @param name The {@code Attribute} identifier.
+	 * @return The associated {@code Attribute} is returned.
+	 * @throws IllegalArgumentException Thrown if neither an {@code Attribute} nor a
+	 *                                  {@link Relation} with given name exists.
+	 */
+	Attribute getAttribute(String name);
+
+	/**
+	 * Returns all {@link Relation}s to other entity types.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getRelations();
+
+	/**
+	 * Returns all {@link Relation}s to allowed parent entity types.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getParentRelations();
+
+	/**
+	 * Returns all available child {@link Relation}s whose relationship is
+	 * {@link RelationType#FATHER_CHILD}.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getChildRelations();
+
+	/**
+	 * Returns all child {@link Relation}s whose relationship is
+	 * {@link RelationType#INFO}.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getInfoRelations();
+
+	/**
+	 * Returns all {@link Relation}s whose relationship is of the given type.
+	 *
+	 * @param relationType The relationship type.
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<Relation> getRelations(RelationType relationType);
+
+	/**
+	 * Returns a {@link Relation} to given target entity type. At first it is tried
+	 * to find a unambiguous {@code Relation} to given {@code EntityType}. If this
+	 * fails it is tried to identify it by the name of the given {@link EntityType}.
+	 *
+	 * @param target Used as identifier.
+	 * @return The associated {@code Relation} is returned.
+	 * @throws IllegalArgumentException Thrown if a relation to given target entity
+	 *                                  type does not exist.
+	 */
+	Relation getRelation(EntityType target);
+
+	/**
+	 * Returns the {@link Relation} with given target entity type and relation name.
+	 *
+	 * @param target The target entity type of the requested {@code Relation}.
+	 * @param name   The name of the requested {@code Relation}.
+	 * @return The associated {@code Relation} is returned.
+	 * @throws IllegalArgumentException Thrown if {@code Relation} with given target
+	 *                                  entity type and name does not exist.
+	 * @see #getRelation(EntityType)
+	 */
+	Relation getRelation(EntityType target, String name);
+
+	/**
+	 * Creates for each {@link Attribute} a corresponding empty {@link Value} and
+	 * returns them mapped by their name.
+	 *
+	 * @return Returns created empty {@code Value}s mapped by their name.
+	 */
+	default Map<String, Value> createValues() {
+		return getAttributes().stream().map(Attribute::createValue)
+				.collect(Collectors.toMap(Value::getName, Function.identity()));
+	}
+
+	/**
+	 * Returns the name of this entity type.
+	 *
+	 * @return The name of this entity type is returned.
+	 */
+	@Override
+	String toString();
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ModelManager.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ModelManager.java
new file mode 100644
index 0000000..2a68f8d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/ModelManager.java
@@ -0,0 +1,97 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.query.Query;
+
+/**
+ * Provides access to any modeled {@link EntityType} within an underlying
+ * application model. A {@link Query}, created by this service, uses these
+ * {@code EntityType}s to access corresponding records.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface ModelManager {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns all available {@link EntityType}s.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	List<EntityType> listEntityTypes();
+
+	/**
+	 * Returns the {@link EntityType} associated with given {@link Entity}.
+	 *
+	 * @param entity Its type name is used as identifier.
+	 * @return {@code EntityType} associated with given entity is returned.
+	 */
+	default EntityType getEntityType(Entity entity) {
+		return getEntityType(entity.getTypeName());
+	}
+
+	/**
+	 * Returns the {@link EntityType} associated with given entity class type.
+	 *
+	 * @param entityClass Used as identifier.
+	 * @return {@code EntityType} associated with given entity class is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} for given type
+	 *                                  does not exist.
+	 */
+	EntityType getEntityType(Class<? extends Entity> entityClass);
+
+	/**
+	 * Returns the {@link EntityType} associated with given entity class and
+	 * {@link ContextType}.
+	 *
+	 * @param entityClass Used as identifier.
+	 * @param contextType Used as identifier.
+	 * @return {@code EntityType} associated with given entity class and {@code
+	 * 		ContextType} is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} for given type
+	 *                                  does not exist.
+	 */
+	EntityType getEntityType(Class<? extends Entity> entityClass, ContextType contextType);
+
+	/**
+	 * Returns the {@link EntityType} identified by given name.
+	 *
+	 * @param name Used as identifier.
+	 * @return {@code EntityType} with given name is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} with given name
+	 *                                  does not exist.
+	 */
+	EntityType getEntityType(String name);
+
+	/**
+	 * Returns the {@link EntityType} identified by given ID.
+	 *
+	 * @param id Used as ID.
+	 * @return {@code EntityType} with given ID is returned.
+	 * @throws IllegalArgumentException Thrown if {@code EntityType} with given ID
+	 *                                  does not exist.
+	 */
+	EntityType getEntityTypeById(String id);
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Relation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Relation.java
new file mode 100644
index 0000000..7800bc0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/Relation.java
@@ -0,0 +1,116 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * Represents a modeled relation.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see RelationType
+ */
+public interface Relation {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * The name of this relation.
+	 *
+	 * @return The name is returned.
+	 */
+	String getName();
+
+	/**
+	 * The source {@link EntityType} of this relation.
+	 *
+	 * @return The source {@code EntityType} is returned.
+	 */
+	EntityType getSource();
+
+	/**
+	 * The target {@link EntityType} of this relation.
+	 *
+	 * @return The target {@code EntityType} is returned.
+	 */
+	EntityType getTarget();
+
+	/**
+	 * Returns the {@link RelationType} type for this relation.
+	 *
+	 * @return The {@code RelationType} is returned.
+	 */
+	RelationType getRelationType();
+
+	/**
+	 * Returns the foreign key {@link Attribute} for this {@link Relation}.
+	 *
+	 * @return The foreign key {@code Attribute} is returned.
+	 */
+	Attribute getAttribute();
+
+	/**
+	 * Creates a new and empty {@link Value} with {@link ValueType#LONG}.
+	 *
+	 * @return Created {@code Value} is returned.
+	 */
+	default Value createValue() {
+		return ValueType.STRING.create(getName());
+	}
+
+	/**
+	 * Returns the name of this relation.
+	 *
+	 * @return Name of this relation is returned.
+	 */
+	@Override
+	String toString();
+
+	/**
+	 * Checks whether this relation is of the same {@link RelationType} as the given
+	 * one and whether the foreign key is in the table of the source entity type
+	 * (or, in other words, if there may be at most 1 related destination object).
+	 *
+	 * @param relationType The {@code RelationType}.
+	 * @return Returns {@code true} this relation's {@code RelationType} is equal
+	 *         with the given one and it is is an outgoing relation.
+	 */
+	boolean isOutgoing(RelationType relationType);
+
+	/**
+	 * Checks whether this relation is of the same {@link RelationType} as the given
+	 * one and whether the foreign key is in the table of the target entity type
+	 * (or, in other words, if there may be more than one related destination
+	 * objects).
+	 *
+	 * @param relationType The {@code RelationType}.
+	 * @return Returns {@code true} this relation's {@code RelationType} is equal
+	 *         with the given one and it is is an incoming relation.
+	 */
+	boolean isIncoming(RelationType relationType);
+
+	/**
+	 * Checks whether this relation is a N to M relation.
+	 * 
+	 * @return Returns {@code true} if this relation is N to M.
+	 */
+	boolean isNtoM();
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationStore.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationStore.java
new file mode 100644
index 0000000..3fb0c6c
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationStore.java
@@ -0,0 +1,108 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.Deletable;
+
+/**
+ * Holds related entities of any kind and keeps track of modifications.
+ */
+public final class RelationStore {
+
+	private final Map<String, List<? extends Deletable>> added = new HashMap<>(0);
+	private final Map<String, List<? extends Deletable>> removed = new HashMap<>(0);
+
+	/**
+	 * Returns current set of related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<String, List<? extends Deletable>> getAdded() {
+		return Collections.unmodifiableMap(added);
+	}
+
+	/**
+	 * Returns current set of removed related children mapped by their type.
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	public Map<String, List<? extends Deletable>> getRemoved() {
+		return Collections.unmodifiableMap(removed);
+	}
+
+	/**
+	 * Returns related child entities of given type.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @return Returned {@code List} is unmodifiable.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> List<T> get(String relation) {
+		return Collections.unmodifiableList((List<T>) added.computeIfAbsent(relation, k -> new ArrayList<>()));
+	}
+
+	/**
+	 * Sorts the child entities with given {@code Comparator}.
+	 *
+	 * @param <T>         Desired entity type.
+	 * @param entityClass Used as identifier.
+	 * @param comparator  Used for sorting.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T extends Deletable> void sort(String relation, Comparator<? super T> comparator) {
+		List<T> children = (List<T>) added.get(relation);
+		if (children != null) {
+			children.sort(comparator);
+		}
+	}
+
+	/**
+	 * Adds given child entity.
+	 *
+	 * @param child The new child.
+	 */
+	@SuppressWarnings("unchecked")
+	public void add(String relation, Deletable relatedEntity) {
+		removed.getOrDefault(relation, new ArrayList<>()).remove(relatedEntity);
+		((List<Deletable>) added.computeIfAbsent(relation, k -> new ArrayList<>())).add(relatedEntity);
+	}
+
+	/**
+	 * Removes given child entity.
+	 *
+	 * @param relatedEntity The child which will be removed.
+	 */
+	@SuppressWarnings("unchecked")
+	public void remove(String relation, Deletable relatedEntity) {
+		added.getOrDefault(relation, new ArrayList<>()).remove(relatedEntity);
+		((List<Deletable>) removed.computeIfAbsent(relation, k -> new ArrayList<>())).add(relatedEntity);
+	}
+
+	/**
+	 * Clean up list of removed entities.
+	 */
+	void apply() {
+		removed.clear();
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationType.java
new file mode 100644
index 0000000..26b9cd5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/adapter/RelationType.java
@@ -0,0 +1,49 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.adapter;
+
+/**
+ * RelationType enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Relation
+ */
+public enum RelationType {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Represents a hierarchical relation between two {@link EntityType}s e.g.:
+	 * {@code Test} and {@code TestStep}.
+	 */
+	FATHER_CHILD,
+
+	/**
+	 * Represents an informational relation between two {@link EntityType}s e.g.:
+	 * {@code Measurement} and {@code ParameterSet}.
+	 */
+	INFO,
+
+	/**
+	 * Represents an inheritance relation between two {@link EntityType}s.
+	 */
+	INHERITANCE
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/file/FileService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/file/FileService.java
new file mode 100644
index 0000000..9a552cc
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/file/FileService.java
@@ -0,0 +1,239 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.file;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.util.Collection;
+
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.FileLink;
+
+/**
+ * Provides stream and download operations to access externally linked files.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public interface FileService {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Sequential download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once.
+	 *
+	 * @param entity    Used for security checks.
+	 * @param target    Must be a directory.
+	 * @param fileLinks Collection of {@code FileLink}s to download.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	default void downloadSequential(Entity entity, Path target, Collection<FileLink> fileLinks) throws IOException {
+		downloadSequential(entity, target, fileLinks, null);
+	}
+
+	/**
+	 * Sequential download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once. The
+	 * download progress may be traced with a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param target           Must be a directory.
+	 * @param fileLinks        Collection of {@code FileLink}s to download.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	void downloadSequential(Entity entity, Path target, Collection<FileLink> fileLinks,
+			ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Parallel download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once.
+	 *
+	 * @param entity    Used for security checks.
+	 * @param target    Must be a directory.
+	 * @param fileLinks Collection of {@code FileLink}s to download.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	default void downloadParallel(Entity entity, Path target, Collection<FileLink> fileLinks) throws IOException {
+		downloadParallel(entity, target, fileLinks, null);
+	}
+
+	/**
+	 * Parallel download of given {@link FileLink}s into given target {@code
+	 * Path}. Remote paths linked multiple times are downloaded only once. The
+	 * download progress may be traced with a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param target           Must be a directory.
+	 * @param fileLinks        Collection of {@code FileLink}s to download.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to download files.
+	 */
+	void downloadParallel(Entity entity, Path target, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException;
+
+
+	/**
+	 * Downloads given {@link FileLink} into given target {@code Path}.
+	 *
+	 * @param entity   Used for security checks.
+	 * @param target   Must be a directory.
+	 * @param fileLink The {@code FileLink} to download.
+	 * @throws IOException Thrown if unable to download file.
+	 */
+	default void download(Entity entity, Path target, FileLink fileLink) throws IOException {
+		download(entity, target, fileLink, null);
+	}
+
+	/**
+	 * Downloads given {@link FileLink} into given target {@code Path}. The download
+	 * progress may be traced with a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param target           Must be a directory.
+	 * @param fileLink         The {@code FileLink} to download.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to download file.
+	 */
+	void download(Entity entity, Path target, FileLink fileLink, ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Opens an {@code InputStream} for given {@link FileLink}. The returned stream
+	 * should be consumed with a try-with-resources statement to ensure the stream
+	 * is closed properly, e.g:
+	 *
+	 * <pre>
+	 * try (InputStream is = openStream(entity, fileLink)) {
+	 * 	// do something useful
+	 * }
+	 * </pre>
+	 *
+	 * @param entity   Used for security checks.
+	 * @param fileLink The {@code FileLink} to be provided as a stream.
+	 * @return A consumable {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to provide as stream.
+	 */
+	default InputStream openStream(Entity entity, FileLink fileLink) throws IOException {
+		return openStream(entity, fileLink, null);
+	}
+
+	/**
+	 * Opens an {@code InputStream} for given {@link FileLink}. The progress of the
+	 * stream consumption may be traced with a progress listener. The returned
+	 * stream should be consumed with a try-with-resources statement to ensure the
+	 * stream is closed properly, e.g:
+	 *
+	 * <pre>
+	 * try (InputStream is = openStream(entity, fileLink)) {
+	 * 	// do something useful
+	 * }
+	 * </pre>
+	 *
+	 * @param entity           Used for security checks.
+	 * @param fileLink         The {@code FileLink} to be provided as a stream.
+	 * @param progressListener The progress listener.
+	 * @return A consumable {@code InputStream} is returned.
+	 * @throws IOException Thrown if unable to provide as stream.
+	 */
+	InputStream openStream(Entity entity, FileLink fileLink, ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Loads the file size for given {@link FileLink}. The file size is stored in
+	 * the given {@code FileLink}.
+	 *
+	 * @param entity   Used for security checks.
+	 * @param fileLink The {@code FileLink} whose file size is requested.
+	 * @throws IOException Thrown if unable to load file size.
+	 */
+	void loadSize(Entity entity, FileLink fileLink) throws IOException;
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * A {@link FileService} consumer may implement this interface to get notified
+	 * about stream or download progress.
+	 */
+	@FunctionalInterface
+	interface ProgressListener {
+
+		/**
+		 * Progress notification.
+		 *
+		 * @param bytes   Number of transferred bytes since last notification.
+		 * @param percent The overall percentage, where percent p &isin; [0.0, 1.0].
+		 */
+		void progress(int bytes, float percent);
+
+	}
+	
+	/**
+	 * Sequential upload of given {@link FileLink}s. Local {@link Path}s linked
+	 * multiple times are uploaded only once. The upload progress may be traced with
+	 * a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param fileLinks        Collection of {@code FileLink}s to upload.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to upload files.
+	 */
+	public void uploadSequential(Entity entity, Collection<FileLink> fileLinks, ProgressListener progressListener) throws IOException;
+
+	/**
+	 * Parallel upload of given {@link FileLink}s. Local {@link Path}s linked
+	 * multiple times are uploaded only once. The upload progress may be traced with
+	 * a progress listener.
+	 *
+	 * @param entity           Used for security checks.
+	 * @param fileLinks        Collection of {@code FileLink}s to upload.
+	 * @param progressListener The progress listener.
+	 * @throws IOException Thrown if unable to upload files.
+	 */
+	public void uploadParallel(Entity entity, Collection<FileLink> fileLinks, ProgressListener progressListener)
+			throws IOException;
+
+	/**
+	 * Deletes given {@link FileLink}s form the remote storage.
+	 *
+	 * @param entity    Used for security checks.
+	 * @param fileLinks Collection of {@code FileLink}s to delete.
+	 */
+	public void delete(Entity entity, Collection<FileLink> fileLinks);
+
+	/**
+	 * Deletes given {@link FileLink} form the remote storage.
+	 *
+	 * @param entity   Used for security checks.
+	 * @param fileLink The {@code FileLink}s to delete.
+	 */
+	public void delete(Entity entity, FileLink fileLink);
+
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/AnyTypeValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/AnyTypeValuesBuilder.java
new file mode 100644
index 0000000..1c2d1ed
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/AnyTypeValuesBuilder.java
@@ -0,0 +1,207 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.time.LocalDateTime;
+
+import org.eclipse.mdm.api.base.model.FileLink;
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder adds values to the {@link WriteRequest} of types listed below.
+ * It is possible to add a sequence where all of its values are valid.
+ * Additionally it is possible to provide a validity flag for each single value.
+ * In either case neither values nor flags are allowed to be {@code
+ * null}. Furthermore if values and flags are given, then their length must be
+ * equal.
+ *
+ * <ul>
+ * <li>{@link ScalarType#STRING}</li>
+ * <li>{@link ScalarType#DATE}</li>
+ * <li>{@link ScalarType#BOOLEAN}</li>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * <li>{@link ScalarType#BYTE_STREAM}</li>
+ * <li>{@link ScalarType#FLOAT_COMPLEX}</li>
+ * <li>{@link ScalarType#DOUBLE_COMPLEX}</li>
+ * <li>{@link ScalarType#FILE_LINK}</li>
+ * <li>{@link ScalarType#BLOB}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class AnyTypeValuesBuilder extends ComplexNumericalValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values will be added to.
+	 */
+	AnyTypeValuesBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@code String} values to the {@link WriteRequest} with a global
+	 * validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code String} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer stringValues(String[] values) {
+		createValues(ScalarType.STRING, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code String} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code String} array sequence.
+	 * @param flags  The validity flags for each {@code String} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer stringValues(String[] values, boolean[] flags) {
+		createValues(ScalarType.STRING, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code LocalDateTime} values to the {@link WriteRequest} with a
+	 * global validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code LocalDateTime} array sequence.
+	 * @return The {@link IndependentBuilder} is returned.
+	 */
+	public IndependentBuilder dateValues(LocalDateTime[] values) {
+		createValues(ScalarType.DATE, values);
+		return new IndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code LocalDateTime} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code LocalDateTime} array sequence.
+	 * @param flags  The validity flags for each {@code LocalDateTime} value.
+	 * @return The {@link IndependentBuilder} is returned.
+	 */
+	public IndependentBuilder dateValues(LocalDateTime[] values, boolean[] flags) {
+		createValues(ScalarType.DATE, values, flags);
+		return new IndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code boolean} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code boolean} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer booleanValues(boolean[] values) {
+		createValues(ScalarType.BOOLEAN, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code boolean} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code boolean} array sequence.
+	 * @param flags  The validity flags for each {@code boolean} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer booleanValues(boolean[] values, boolean[] flags) {
+		createValues(ScalarType.BOOLEAN, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code byte[]} values to the {@link WriteRequest} with a global
+	 * validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code byte[]} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer byteStreamValues(byte[][] values) {
+		createValues(ScalarType.BYTE_STREAM, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code byte[]} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code byte[]} array sequence.
+	 * @param flags  The validity flags for each {@code byte[]} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer byteStreamValues(byte[][] values, boolean[] flags) {
+		createValues(ScalarType.BYTE_STREAM, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link FileLink} values to the {@link WriteRequest} with a global
+	 * validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code FileLink} array sequence.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer fileLinkValues(FileLink[] values) {
+		createValues(ScalarType.FILE_LINK, values);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link FileLink} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code FileLink} array sequence.
+	 * @param flags  The validity flags for each {@code FileLink} value.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer fileLinkValues(FileLink[] values, boolean[] flags) {
+		createValues(ScalarType.FILE_LINK, values, flags);
+		return new WriteRequestFinalizer(getWriteRequest());
+	}
+
+	// TODO: is it possible to provide a blob for each row or is the blob for
+	// the whole column?!
+	// we assume the latter - one blob for the whole column!
+	public WriteRequestFinalizer blobValue(Object values) {
+		createValues(ScalarType.BLOB, values);
+		throw new UnsupportedOperationException("Not implemented.");
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/BaseValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/BaseValuesBuilder.java
new file mode 100644
index 0000000..a9f3bca
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/BaseValuesBuilder.java
@@ -0,0 +1,100 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.lang.reflect.Array;
+
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This is a base values builder provides methods for configuring values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+abstract class BaseValuesBuilder {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final WriteRequest writeRequest;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values and corresponding
+	 *                     {@link ScalarType} will be applied to.
+	 */
+	BaseValuesBuilder(WriteRequest writeRequest) {
+		this.writeRequest = writeRequest;
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Adds given value sequence and sets the corresponding {@link ScalarType} as
+	 * the raw {@code ScalarType}.
+	 *
+	 * @param scalarType The {@code ScalarType}.
+	 * @param values     The array value sequence must be assignment compatible with
+	 *                   the type represented by the given {@code ScalarType}.
+	 */
+	protected final void createValues(ScalarType scalarType, Object values) {
+		if (values == null) {
+			throw new IllegalArgumentException("Values is not allowed to be null.");
+		}
+
+		getWriteRequest().setRawScalarType(scalarType);
+		getWriteRequest().setValues(values);
+	}
+
+	/**
+	 * Adds given value sequence, associated validity flags and sets the
+	 * corresponding {@link ScalarType} as the raw {@code ScalarType}.
+	 *
+	 * @param scalarType The {@code ScalarType}.
+	 * @param values     The array value sequence must be assignment compatible with
+	 *                   the type represented by the given {@code ScalarType}.
+	 * @param flags      The validity flags for each value in the values sequence.
+	 */
+	protected final void createValues(ScalarType scalarType, Object values, boolean[] flags) {
+		if (values == null || flags == null) {
+			throw new IllegalArgumentException("Neither values nor flags are allowed to be null.");
+		} else if (Array.getLength(values) != flags.length) {
+			throw new IllegalArgumentException("Length of values and flags must be equal.");
+		}
+
+		getWriteRequest().setRawScalarType(scalarType);
+		getWriteRequest().setValues(values, flags);
+	}
+
+	/**
+	 * Returns the {@link WriteRequest}.
+	 *
+	 * @return The {@code WriteRequest} is returned.
+	 */
+	protected final WriteRequest getWriteRequest() {
+		return writeRequest;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ComplexNumericalValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ComplexNumericalValuesBuilder.java
new file mode 100644
index 0000000..f5b37ea
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ComplexNumericalValuesBuilder.java
@@ -0,0 +1,115 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.DoubleComplex;
+import org.eclipse.mdm.api.base.model.FloatComplex;
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder adds values to the {@link WriteRequest} of types listed below.
+ * It is possible to add a sequence where all of its values are valid.
+ * Additionally it is possible to provide a validity flag for each single value.
+ * In either case neither values nor flags are allowed to be {@code
+ * null}. Furthermore if values and flags are given, then their length must be
+ * equal.
+ *
+ * <ul>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * <li>{@link ScalarType#FLOAT_COMPLEX}</li>
+ * <li>{@link ScalarType#DOUBLE_COMPLEX}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ComplexNumericalValuesBuilder extends NumericalValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values will be added to.
+	 */
+	ComplexNumericalValuesBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@link FloatComplex} values to the {@link WriteRequest} with a
+	 * global validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code FloatComplex} array sequence.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder floatComplexValues(FloatComplex[] values) {
+		createValues(ScalarType.FLOAT_COMPLEX, values);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link FloatComplex} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code FloatComplex} array sequence.
+	 * @param flags  The validity flags for each {@code FloatComplex} value.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder floatComplexValues(FloatComplex[] values, boolean[] flags) {
+		createValues(ScalarType.FLOAT_COMPLEX, values, flags);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link DoubleComplex} values to the {@link WriteRequest} with a
+	 * global validity flag, which means the given sequence does not contain any
+	 * {@code null} values.
+	 *
+	 * @param values The {@code DoubleComplex} array sequence.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder doubleComplexValues(DoubleComplex[] values) {
+		createValues(ScalarType.DOUBLE_COMPLEX, values);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@link DoubleComplex} values to the {@link WriteRequest} with a
+	 * validity flag for each given value.
+	 *
+	 * @param values The {@code DoubleComplex} array sequence.
+	 * @param flags  The validity flags for each {@code DoubleComplex} value.
+	 * @return The {@link UnitBuilder} is returned.
+	 */
+	public final UnitBuilder doubleComplexValues(DoubleComplex[] values, boolean[] flags) {
+		createValues(ScalarType.DOUBLE_COMPLEX, values, flags);
+		return new UnitBuilder(getWriteRequest());
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ExternalComponent.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ExternalComponent.java
new file mode 100644
index 0000000..822e26a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ExternalComponent.java
@@ -0,0 +1,20 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+public final class ExternalComponent {
+
+	// TODO
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/IndependentBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/IndependentBuilder.java
new file mode 100644
index 0000000..90942cd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/IndependentBuilder.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder allows to configure numerically sortable measured values to be
+ * independent, which means the measured values do not depend on those of other
+ * {@link Channel}s within their common {@link ChannelGroup}. The numerically
+ * sortable types are listed below:
+ *
+ * <ul>
+ * <li>{@link ScalarType#DATE}</li>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class IndependentBuilder extends WriteRequestFinalizer {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest}, whose measured values of the
+	 *                     underlying {@link Channel} may be marked as independent.
+	 */
+	IndependentBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Triggers the measured values of the underlying {@link Channel} to be
+	 * independent.
+	 *
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public final WriteRequestFinalizer independent() {
+		getWriteRequest().setIndependent();
+		return this;
+	}
+
+	/**
+	 * Triggers the measured values of the underlying {@link Channel} to be
+	 * independent or not, depending on the value specified.
+	 *
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public final WriteRequestFinalizer independent(boolean independent) {
+		getWriteRequest().setIndependent(independent);
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/NumericalValuesBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/NumericalValuesBuilder.java
new file mode 100644
index 0000000..45baeb0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/NumericalValuesBuilder.java
@@ -0,0 +1,209 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.ScalarType;
+
+/**
+ * This builder adds values to the {@link WriteRequest} of types listed below.
+ * It is possible to add a sequence where all of its values are valid.
+ * Additionally it is possible to provide a validity flag for each single value.
+ * In either case neither values nor flags are allowed to be {@code
+ * null}. Furthermore if values and flags are given, then their length must be
+ * equal.
+ *
+ * <ul>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class NumericalValuesBuilder extends BaseValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} given values will be added to.
+	 */
+	NumericalValuesBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Adds given {@code byte} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code byte} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder byteValues(byte[] values) {
+		createValues(ScalarType.BYTE, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code byte} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code byte} array sequence.
+	 * @param flags  The validity flags for each {@code byte} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder byteValues(byte[] values, boolean[] flags) {
+		createValues(ScalarType.BYTE, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code short} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code short} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder shortValues(short[] values) {
+		createValues(ScalarType.SHORT, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code short} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code short} array sequence.
+	 * @param flags  The validity flags for each {@code short} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder shortValues(short[] values, boolean[] flags) {
+		createValues(ScalarType.SHORT, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code int} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code int} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder integerValues(int[] values) {
+		createValues(ScalarType.INTEGER, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code int} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code int} array sequence.
+	 * @param flags  The validity flags for each {@code int} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder integerValues(int[] values, boolean[] flags) {
+		createValues(ScalarType.INTEGER, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code long} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code long} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder longValues(long[] values) {
+		createValues(ScalarType.LONG, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code long} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code long} array sequence.
+	 * @param flags  The validity flags for each {@code long} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder longValues(long[] values, boolean[] flags) {
+		createValues(ScalarType.LONG, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code float} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code float} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder floatValues(float[] values) {
+		createValues(ScalarType.FLOAT, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code float} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code float} array sequence.
+	 * @param flags  The validity flags for each {@code float} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder floatValues(float[] values, boolean[] flags) {
+		createValues(ScalarType.FLOAT, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code double} values to the {@link WriteRequest} with a global
+	 * validity flag.
+	 *
+	 * @param values The {@code double} array sequence.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder doubleValues(double[] values) {
+		createValues(ScalarType.DOUBLE, values);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Adds given {@code double} values to the {@link WriteRequest} with a validity
+	 * flag for each given value.
+	 *
+	 * @param values The {@code double} array sequence.
+	 * @param flags  The validity flags for each {@code double} value.
+	 * @return The {@link UnitIndependentBuilder} is returned.
+	 */
+	public final UnitIndependentBuilder doubleValues(double[] values, boolean[] flags) {
+		createValues(ScalarType.DOUBLE, values, flags);
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequest.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequest.java
new file mode 100644
index 0000000..26fb806
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequest.java
@@ -0,0 +1,268 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * This class provides all required informations to load measured values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class ReadRequest {
+	public enum ValuesMode {
+		/**
+		 * MeasuredValues will contain the final values, calculated for non-explicit
+		 * sequence representations using generation parameters and, if applicable, the
+		 * raw values. No generation parameters are returned in the resulting
+		 * MeasuredValues, {@link SequenceRepresentation} will be EXPLICIT.
+		 */
+		CALCULATED,
+		/**
+		 * MeasuredValues will contain the (raw) values and generation parameters as
+		 * present in the storage.
+		 */
+		STORAGE
+	}
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<Channel, Unit> channels = new HashMap<>();
+	private final ChannelGroup channelGroup;
+
+	private boolean loadAllChannels;
+
+	private int requestSize = 100_000;
+	private int startIndex;
+
+	private ValuesMode valuesMode = ValuesMode.CALCULATED;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param readRequest The previous {@link ReadRequest}.
+	 */
+	ReadRequest(ReadRequest readRequest) {
+		this(readRequest.getChannelGroup());
+		channels.putAll(readRequest.getChannels());
+		loadAllChannels = readRequest.loadAllChannels;
+		requestSize = readRequest.getRequestSize();
+		startIndex = readRequest.getStartIndex() + readRequest.getRequestSize();
+		valuesMode = readRequest.getValuesMode();
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param channelGroup The {@link ChannelGroup} is the source entity to access
+	 *                     measured values.
+	 */
+	private ReadRequest(ChannelGroup channelGroup) {
+		this.channelGroup = channelGroup;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link ReadRequestBuilder} with the given {@link ChannelGroup}
+	 * as the source entity for the requested measured values.
+	 *
+	 * <pre>
+	 * ReadRequest readRequest1 = ReadRequest.create(ChannelGroup).allChannels() // load
+	 * 																			// values
+	 * 																			// of
+	 * 																			// all
+	 * 																			// related
+	 * 																			// channels
+	 * 		.allValues() // load all values of each channel
+	 * 		.get();
+	 *
+	 * ReadRequest readRequest2 = ReadRequest.create(ChannelGroup).channels(channel1, channel2) // load
+	 * 																							// measured
+	 * 																							// values
+	 * 																							// of
+	 * 																							// these
+	 * 																							// channels
+	 * 		.requestSize(1_000) // load 1000 values of each channel (default
+	 * 							// is 100_000)
+	 * 		.get();
+	 * </pre>
+	 *
+	 * @param channelGroup Used to access measured values.
+	 * @return Returns the {@link ReadRequestBuilder}.
+	 */
+	public static ReadRequestBuilder create(ChannelGroup channelGroup) {
+		return new ReadRequestBuilder(new ReadRequest(channelGroup));
+	}
+
+	/**
+	 * Returns the selected {@link Channel}s whose values will be loaded and the
+	 * corresponding {@link Unit} configuration.
+	 *
+	 * @return The returned {@code Map} is empty, if this request is configured to
+	 *         load values of all related {@code Channel}s.
+	 */
+	public Map<Channel, Unit> getChannels() {
+		return Collections.unmodifiableMap(channels);
+	}
+
+	/**
+	 * Returns the {@link ChannelGroup} which will be used as the source entity to
+	 * access measured values.
+	 *
+	 * @return The measured values source, the {@code ChannelGroup} is returned.
+	 */
+	public ChannelGroup getChannelGroup() {
+		return channelGroup;
+	}
+
+	/**
+	 * Checks whether to load measured values of all related {@link Channel}s.
+	 *
+	 * @return True if this request is configured to load values of all {@code
+	 * 		Channel}s.
+	 */
+	public boolean isLoadAllChannels() {
+		return loadAllChannels;
+	}
+
+	/**
+	 * Returns the number of values that are loaded per {@link Channel} .
+	 *
+	 * @return The number of values per {@code Channel} per is returned.
+	 */
+	public int getRequestSize() {
+		return requestSize;
+	}
+
+	/**
+	 * Returns the overall index of the measured values within the underlying
+	 * {@link ChannelGroup}. This index is used while processing this request and
+	 * means how many values of the values sequences will be skipped.
+	 *
+	 * @return The overall start index is returned.
+	 */
+	public int getStartIndex() {
+		return startIndex;
+	}
+
+	/**
+	 * Returns the {link ValuesMode} for measured values retrieval.
+	 *
+	 * @return The valuesMode is returned.
+	 */
+	public ValuesMode getValuesMode() {
+		return valuesMode;
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Adds a new {@link Channel} whose measured values have to be loaded. The
+	 * measured values will be retrieved in the unit they were stored.
+	 *
+	 * @param channel This {@code Channel} has to related to the underlying
+	 *                {@link ChannelGroup}.
+	 */
+	void addChannel(Channel channel) {
+		addChannel(channel, channel.getUnit());
+	}
+
+	/**
+	 * Adds a new {@link Channel} whose measured values have to be loaded. The
+	 * measured values will be retrieved in the given unit.
+	 *
+	 * <p>
+	 * <b>Note:</b> The processing of this request may fail if it is not possible to
+	 * convert the values.
+	 *
+	 * @param channel This {@code Channel} has to related to the underlying
+	 *                {@link ChannelGroup}.
+	 * @param unit    {@code Unit} the measured values have to be loaded in.
+	 */
+	void addChannel(Channel channel, Unit unit) {
+		channels.put(channel, unit);
+	}
+
+	/**
+	 * Configures this request to retrieve measured values of all related
+	 * {@link Channel}s.
+	 */
+	void setLoadAllChannels() {
+		loadAllChannels = true;
+		channels.clear();
+	}
+
+	/**
+	 * Sets the number of values that will be loaded per {@link Channel} while
+	 * processing this request.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the request size is zero, then all available measured values
+	 * will be loaded for each configured {@link Channel}.
+	 *
+	 * @param requestSize The number of values loaded per {@code Channel}.
+	 */
+	void setRequestSize(int requestSize) {
+		this.requestSize = requestSize;
+	}
+
+	/**
+	 * Sets the number of values that will be skipped.
+	 *
+	 * @param startIndex The number of values that will be skipped.
+	 */
+	void setStartIndex(int startIndex) {
+		this.startIndex = startIndex;
+	}
+
+	/**
+	 * Sets the {@link ValuesMode} for measured values retrieval.
+	 * 
+	 * @param valuesMode The {@link VAluesMode} to set.
+	 */
+	void setValuesMode(ValuesMode valuesMode) {
+		this.valuesMode = valuesMode;
+	}
+
+	/**
+	 * Checks whether there are still more values to retrieve.
+	 *
+	 * @return Returns true if there are more values to retrieve.
+	 */
+	boolean hasNext() {
+		return getStartIndex() + getRequestSize() < getChannelGroup().getNumberOfValues().intValue();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestBuilder.java
new file mode 100644
index 0000000..f25c615
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestBuilder.java
@@ -0,0 +1,192 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.mdm.api.base.massdata.ReadRequest.ValuesMode;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * Builds measured values read request configurations.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class ReadRequestBuilder {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ReadRequest readRequest;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param readRequest The {@link ReadRequest} that will be configured.
+	 */
+	ReadRequestBuilder(ReadRequest readRequest) {
+		this.readRequest = readRequest;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Configures the {@link ReadRequest} to retrieve measured values of all related
+	 * {@link Channel}s.
+	 *
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder allChannels() {
+		readRequest.setLoadAllChannels();
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Channel}s to the underlying {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> {@code Channel}s added with this method will be ignored, once
+	 * {@link #allChannels()} was called.
+	 *
+	 * @param channels The {@code Channel}s whose measured values will be loaded.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder channels(List<Channel> channels) {
+		channels.forEach(readRequest::addChannel);
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Channel}s to the underlying {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> {@code Channel}s added with this method will be ignored, once
+	 * {@link #allChannels()} was called.
+	 *
+	 * @param channels The {@code Channel}s whose measured values will be loaded.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder channels(Channel... channels) {
+		Arrays.stream(channels).forEach(readRequest::addChannel);
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Channel} to the underlying {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> {@code Channel} added with this method will be ignored, once
+	 * {@link #allChannels()} was called.
+	 *
+	 * @param channel The {@code Channel} whose measured values will be loaded.
+	 * @param unit    The unit of the loaded measured values.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder channel(Channel channel, Unit unit) {
+		readRequest.addChannel(channel, unit);
+		return this;
+	}
+
+	/**
+	 * Configures the valuesMode.
+	 * 
+	 * @param valuesMode {@link ValuesMode} to use for the read request.
+	 * @return This builder is returned.
+	 */
+	public ReadRequestBuilder valuesMode(ReadRequest.ValuesMode valuesMode) {
+		readRequest.setValuesMode(valuesMode);
+		return this;
+	}
+
+	/**
+	 * Configures the {@link ReadRequest} to load all measured values of each
+	 * configured {@link Channel} and returns the configured {@code
+	 * ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> Before calling this the {@code Channel}s whose measured values
+	 * have to be loaded must be configured.
+	 *
+	 * @return This builder is returned.
+	 */
+	public ReadRequest allValues() {
+		readRequest.setStartIndex(0);
+		readRequest.setRequestSize(0);
+		return readRequest;
+	}
+
+	/**
+	 * Configures the {@link ReadRequest} to load the specified number of values for
+	 * each {@link Channel}. this is a terminal operation returning the built
+	 * {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the request size is zero, then all available measured values
+	 * will be loaded for each configured {@link Channel}.
+	 *
+	 * @param requestSize The request size.
+	 * @return the {@link ReadRequest}
+	 * @throws IllegalArgumentException Thrown if the request size is smaller than
+	 *                                  0.
+	 */
+	public ReadRequest values(int requestSize) {
+		readRequest.setStartIndex(0);
+		readRequest.setRequestSize(requestSize);
+		return readRequest;
+	}
+
+	/**
+	 * Configures the {@link ReadRequest} to load the specified number of values
+	 * from a specified start index for each {@link Channel}. this is a terminal
+	 * operation returning the built {@link ReadRequest}.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the request size is zero, then all available measured values
+	 * will be loaded for each configured {@link Channel}.
+	 *
+	 * @param startIndex  The start index.
+	 * @param requestSize The request size.
+	 * @return the {@link ReadRequest}
+	 * @throws IllegalArgumentException Thrown if the request size is smaller than 0
+	 *                                  or if the start index is smaller than 0.
+	 */
+	public ReadRequest values(int startIndex, int requestSize) {
+		readRequest.setStartIndex(startIndex);
+		readRequest.setRequestSize(requestSize);
+		return readRequest;
+	}
+
+	/**
+	 * Returns an {@link ReadRequestIterable} to iterate over all available
+	 * {@link ReadRequest}s.
+	 *
+	 * @return The {@code ReadRequestIterable} is returned.
+	 */
+	public ReadRequestIterable createIterable() {
+		return new ReadRequestIterable(readRequest);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestIterable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestIterable.java
new file mode 100644
index 0000000..5e627b4
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/ReadRequestIterable.java
@@ -0,0 +1,84 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/**
+ * This is an read request iterable for comfortable processing of subsequent
+ * {@link ReadRequest}s
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class ReadRequestIterable implements Iterable<ReadRequest>, Iterator<ReadRequest> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private ReadRequest readRequest;
+	private int count;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param readRequest The {@link ReadRequest}.
+	 */
+	ReadRequestIterable(ReadRequest readRequest) {
+		this.readRequest = readRequest;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean hasNext() {
+		return count == 0 || readRequest.hasNext();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public ReadRequest next() {
+		if (hasNext()) {
+			readRequest = count == 0 ? readRequest : new ReadRequest(readRequest);
+			count++;
+			return readRequest;
+		}
+
+		throw new NoSuchElementException("Subsequent read request is not available.");
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Iterator<ReadRequest> iterator() {
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitBuilder.java
new file mode 100644
index 0000000..4335172
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitBuilder.java
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * This builder allows to specify a source {@link Unit} which is different to
+ * the origin {@code Unit} of the underlying {@link Channel}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class UnitBuilder extends WriteRequestFinalizer {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest}, whose measured value's source
+	 *                     {@link Unit} may be defined.
+	 */
+	UnitBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Sets a source {@link Unit} for the previously defined measured values.
+	 *
+	 * @param sourceUnit The source {@code Unit}.
+	 * @return The {@link WriteRequestFinalizer} is returned.
+	 */
+	public WriteRequestFinalizer sourceUnit(Unit sourceUnit) {
+		getWriteRequest().setSourceUnit(sourceUnit);
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitIndependentBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitIndependentBuilder.java
new file mode 100644
index 0000000..f0f15db
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/UnitIndependentBuilder.java
@@ -0,0 +1,75 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * This builder allows to specify a source {@link Unit} which is different to
+ * the origin {@code Unit} of the underlying {@link Channel}. In Addition to
+ * that this builder allows to configure numerically sortable measured values to
+ * be independent, which means the measured values do not depend on those of
+ * other {@link Channel}s within their common {@link ChannelGroup}. The
+ * numerically sortable types are listed below:
+ *
+ * <ul>
+ * <li>{@link ScalarType#DATE}</li>
+ * <li>{@link ScalarType#BYTE}</li>
+ * <li>{@link ScalarType#SHORT}</li>
+ * <li>{@link ScalarType#INTEGER}</li>
+ * <li>{@link ScalarType#LONG}</li>
+ * <li>{@link ScalarType#FLOAT}</li>
+ * <li>{@link ScalarType#DOUBLE}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class UnitIndependentBuilder extends IndependentBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} whose measured values source
+	 *                     {@link Unit} may be changed or marked as independent.
+	 */
+	UnitIndependentBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Sets a source {@link Unit} for the previously defined measured values.
+	 *
+	 * @param sourceUnit The source {@code Unit}.
+	 * @return The {@link IndependentBuilder} is returned.
+	 */
+	public IndependentBuilder sourceUnit(Unit sourceUnit) {
+		getWriteRequest().setSourceUnit(sourceUnit);
+		return this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequest.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequest.java
new file mode 100644
index 0000000..a08bd99
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequest.java
@@ -0,0 +1,370 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.mdm.api.base.model.AxisType;
+import org.eclipse.mdm.api.base.model.Channel;
+import org.eclipse.mdm.api.base.model.ChannelGroup;
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+import org.eclipse.mdm.api.base.model.Unit;
+
+/**
+ * Holds required data to write mass data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class WriteRequest {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final List<ExternalComponent> externalComponents = new ArrayList<>();
+	private final ChannelGroup channelGroup;
+	private final Channel channel;
+	private final AxisType axisType;
+
+	private SequenceRepresentation sequenceRepresentation;
+	private double[] generationParameters;
+	private boolean independent;
+
+	private ScalarType rawScalarType;
+	private Object values;
+	private boolean allValid;
+	private boolean[] flags;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param channelGroup The {@link ChannelGroup} for this request.
+	 * @param channel      The {@link Channel} specified mass data will be dedicated
+	 *                     to.
+	 * @param axisType     The {@link AxisType} of the written mass data.
+	 */
+	private WriteRequest(ChannelGroup channelGroup, Channel channel, AxisType axisType) {
+		this.channelGroup = channelGroup;
+		this.channel = channel;
+		this.axisType = axisType;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Starts a new {@link WriteRequest} by returning a {@link WriteRequestBuilder}.
+	 *
+	 * @param channelGroup The {@link ChannelGroup} for this request.
+	 * @param channel      The {@link Channel} specified mass data will be dedicated
+	 *                     to.
+	 * @param axisType     The {@link AxisType} of the written mass data.
+	 * @return A {@code WriteRequestBuilder} is returned.
+	 */
+	public static WriteRequestBuilder create(ChannelGroup channelGroup, Channel channel, AxisType axisType) {
+		return new WriteRequestBuilder(new WriteRequest(channelGroup, channel, axisType));
+	}
+
+	/**
+	 * Returns the {@link ChannelGroup} of this request.
+	 *
+	 * @return The {@code ChannelGroup} is returned.
+	 */
+	public ChannelGroup getChannelGroup() {
+		return channelGroup;
+	}
+
+	/**
+	 * Returns the {@link Channel} of this request.
+	 *
+	 * @return The {@code Channel} is returned.
+	 */
+	public Channel getChannel() {
+		return channel;
+	}
+
+	/**
+	 * Returns the {@link AxisType} of this request.
+	 *
+	 * @return The {@code AxisType} is returned.
+	 */
+	public AxisType getAxisType() {
+		return axisType;
+	}
+
+	/**
+	 * Returns the {@link SequenceRepresentation} of this request.
+	 *
+	 * @return The {@code SequenceRepresentation} is returned.
+	 */
+	public SequenceRepresentation getSequenceRepresentation() {
+		return sequenceRepresentation;
+	}
+
+	/**
+	 * Returns the generation parameters of this request. The length of the returned
+	 * array depends on the {@link SequenceRepresentation} of this request.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> In case of an implicit sequence representation this method will
+	 * always return an empty array since these generation parameters are correctly
+	 * typed and stored as measured values.
+	 *
+	 * @return If none available, then an empty array is returned.
+	 */
+	public double[] getGenerationParameters() {
+		return generationParameters == null ? new double[0] : generationParameters.clone();
+	}
+
+	/**
+	 * Returns the independent flag of this request.
+	 *
+	 * @return Returns {@code true} if the measured values do not depend on those of
+	 *         other {@link Channel}s within their common {@link ChannelGroup}.
+	 */
+	public boolean isIndependent() {
+		return independent;
+	}
+
+	/**
+	 * Checks whether this request has measured values.
+	 *
+	 * @return Returns {@code true} if {@link SequenceRepresentation#isExternal()}
+	 *         returns {@code false}.
+	 * @see #hasExternalComponents()
+	 */
+	public boolean hasValues() {
+		return !getSequenceRepresentation().isExternal();
+	}
+
+	/**
+	 * Returns the stored measured values.
+	 *
+	 * @return The measured values are returned.
+	 * @throws IllegalStateException Thrown if values are not available.
+	 */
+	public Object getValues() {
+		if (hasValues()) {
+			return values;
+		}
+
+		throw new IllegalStateException("Values are not available.");
+	}
+
+	/**
+	 * Checks whether this request has measured values, stored in externally linked
+	 * files.
+	 *
+	 * @return Returns {@code true} if {@link SequenceRepresentation#isExternal()}
+	 *         returns {@code true}.
+	 * @see #hasValues()
+	 */
+	public boolean hasExternalComponents() {
+		return getSequenceRepresentation().isExternal();
+	}
+
+	/**
+	 * Returns the configurations for measured values stored in externally
+	 * referenced files.
+	 * 
+	 * @return Returned {@code List} is unmodifiable.
+	 * @throws IllegalStateException Thrown if configurations are not available.
+	 */
+	public List<ExternalComponent> getExternalComponents() {
+		if (!hasExternalComponents()) {
+			throw new IllegalStateException("External components are not available.");
+		}
+
+		return Collections.unmodifiableList(externalComponents);
+	}
+
+	/**
+	 * Returns the {@link ScalarType} of the stored measured value sequence.
+	 *
+	 * @return The raw {@code ScalarType} is returned.
+	 */
+	public ScalarType getRawScalarType() {
+		return rawScalarType;
+	}
+
+	/**
+	 * Returns the calculated {@link ScalarType} which reflects the final
+	 * {@code ScalarType} of the generated measured value sequence. If
+	 * {@link #getGenerationParameters()} returns a not empty array and
+	 * {@link #getRawScalarType()} is an integer type (byte, short, int, long), then
+	 * the returned {@code ScalarType} is bumped to the next suitable floating point
+	 * type as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE} -&gt; {@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#SHORT} -&gt; {@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#INTEGER} -&gt; {@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#LONG} -&gt; {@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * @return The calculated {@code ScalarType} is returned.
+	 */
+	public ScalarType getCalculatedScalarType() {
+		if (getGenerationParameters().length > 0 && getRawScalarType().isIntegerType()) {
+			return getRawScalarType().isLong() ? ScalarType.DOUBLE : ScalarType.FLOAT;
+		}
+
+		return getRawScalarType();
+	}
+
+	/**
+	 * Checks whether all measured values within the whole sequence are valid. If
+	 * this method returns {@code true}, then {@link #getFlags()} will return an
+	 * empty array.
+	 *
+	 * @return Returns {@code true} if all measured values are valid.
+	 * @see #getFlags()
+	 */
+	public boolean areAllValid() {
+		return allValid;
+	}
+
+	/**
+	 * Returns the validity flags sequence for the stored measured values. If
+	 * {@link #areAllValid()} returns {@code false} this method will return an array
+	 * with the same length as the measured values sequence, where each flag
+	 * indicates whether the corresponding measured value is valid or not.
+	 *
+	 * @return The validity flags sequence is returned.
+	 * @see #allValid
+	 */
+	public boolean[] getFlags() {
+		return flags.clone();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Sets the {@link SequenceRepresentation} for this request.
+	 *
+	 * @param sequenceRepresentation The {@link SequenceRepresentation}.
+	 */
+	void setSequenceRepresentation(SequenceRepresentation sequenceRepresentation) {
+		this.sequenceRepresentation = sequenceRepresentation;
+	}
+
+	/**
+	 * Sets generation parameters for this request.
+	 *
+	 * @param generationParameters The generation parameters.
+	 */
+	void setGenerationParameters(double[] generationParameters) {
+		this.generationParameters = generationParameters.clone();
+	}
+
+	/**
+	 * Sets the independent flag for this request.
+	 */
+	void setIndependent() {
+		independent = true;
+	}
+
+	/**
+	 * Sets the independent flag for this request to the value specified.
+	 * 
+	 * @param independent The independent flag.
+	 */
+	void setIndependent(boolean independent) {
+		this.independent = independent;
+	}
+
+	/**
+	 * Triggers an adjustment of the generation parameters and modification of the
+	 * {@link SequenceRepresentation} of this request to match the {@link Channel}s
+	 * default {@link Unit}.
+	 *
+	 * @param sourceUnit The {@link Unit} of the measured values.
+	 */
+	void setSourceUnit(Unit sourceUnit) {
+		throw new UnsupportedOperationException("Conversion between units is not implemented yet.");
+	}
+
+	/**
+	 * Sets the raw {@link ScalarType} for this request.
+	 *
+	 * @param rawScalarType The {@link ScalarType}.
+	 */
+	void setRawScalarType(ScalarType rawScalarType) {
+		this.rawScalarType = rawScalarType;
+	}
+
+	/**
+	 * Sets the measured values sequence where each value in the sequence is
+	 * expected to be valid.
+	 *
+	 * @param values The measured value sequence.
+	 * @throws IllegalStateException Thrown if {@link #hasValues()} returns
+	 *                               {@code false}.
+	 */
+	void setValues(Object values) {
+		if (hasValues()) {
+			this.values = values;
+			allValid = true;
+		} else {
+			throw new IllegalStateException("Measured values stored in externally linked files expected.");
+		}
+	}
+
+	/**
+	 * Sets the measured values sequence where each value's validity is specified in
+	 * the given flags array.
+	 *
+	 * @param values The measured value sequence.
+	 * @param flags  The validity flag sequence.
+	 * @throws IllegalStateException Thrown if {@link #hasValues()} returns
+	 *                               {@code false}.
+	 */
+	void setValues(Object values, boolean[] flags) {
+		if (hasValues()) {
+			this.values = values;
+			this.flags = flags.clone();
+		} else {
+			throw new IllegalStateException("Measured values stored in externally linked files expected.");
+		}
+	}
+
+	/**
+	 * Adds a configuration for measured values stored in externally linked files.
+	 *
+	 * @param externalComponent The new configuration.
+	 * @throws IllegalStateException Thrown if {@link #hasExternalComponents()}
+	 *                               returns {@code false}.
+	 */
+	void addExternalComponent(ExternalComponent externalComponent) {
+		if (hasExternalComponents()) {
+			externalComponents.add(externalComponent);
+		} else {
+			throw new IllegalStateException("Measured values expected");
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestBuilder.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestBuilder.java
new file mode 100644
index 0000000..63aebc6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestBuilder.java
@@ -0,0 +1,271 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+import org.eclipse.mdm.api.base.model.ScalarType;
+import org.eclipse.mdm.api.base.model.SequenceRepresentation;
+
+/**
+ * Builds measured values write request configurations.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class WriteRequestBuilder extends BaseValuesBuilder {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The {@link WriteRequest} which will be configured.
+	 */
+	WriteRequestBuilder(WriteRequest writeRequest) {
+		super(writeRequest);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Configures the {@link WriteRequest} to create an explicit sequence of
+	 * measured values.
+	 *
+	 * @return An {@link AnyTypeValuesBuilder} is returned.
+	 * @see SequenceRepresentation#EXPLICIT
+	 */
+	public AnyTypeValuesBuilder explicit() {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.EXPLICIT);
+		return new AnyTypeValuesBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create an implicit constant sequence
+	 * of measured values. An implicit sequence allows only numerical
+	 * {@link ScalarType}s as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE}</li>
+	 * <li>{@link ScalarType#SHORT}</li>
+	 * <li>{@link ScalarType#INTEGER}</li>
+	 * <li>{@link ScalarType#LONG}</li>
+	 * <li>{@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> Given offset will be cast to an assignment compatible type.
+	 *
+	 * @param scalarType The {@code ScalarType} of each single measured value in the
+	 *                   sequence.
+	 * @param offset     The constant value.
+	 * @return An {@link UnitBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is not
+	 *                                  supported.
+	 * @see SequenceRepresentation#IMPLICIT_CONSTANT
+	 */
+	public UnitBuilder implicitConstant(ScalarType scalarType, double offset) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.IMPLICIT_CONSTANT);
+
+		Object values;
+		if (scalarType.isByte()) {
+			values = new byte[] { (byte) offset };
+		} else if (scalarType.isShort()) {
+			values = new short[] { (short) offset };
+		} else if (scalarType.isInteger()) {
+			values = new int[] { (int) offset };
+		} else if (scalarType.isLong()) {
+			values = new long[] { (long) offset };
+		} else if (scalarType.isFloat()) {
+			values = new float[] { (float) offset };
+		} else if (scalarType.isDouble()) {
+			values = new double[] { offset };
+		} else {
+			throw new IllegalArgumentException("Scalar type '" + scalarType + "' is not supported.");
+		}
+		createValues(scalarType, values);
+
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create an implicit linear sequence of
+	 * measured values. An implicit sequence allows only numerical
+	 * {@link ScalarType}s as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE}</li>
+	 * <li>{@link ScalarType#SHORT}</li>
+	 * <li>{@link ScalarType#INTEGER}</li>
+	 * <li>{@link ScalarType#LONG}</li>
+	 * <li>{@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> Given start and increment will be cast to an assignment
+	 * compatible type.
+	 *
+	 * @param scalarType The {@code ScalarType} of each single measured value in the
+	 *                   sequence.
+	 * @param start      The start value of the line.
+	 * @param increment  The gradient of the line.
+	 * @return An {@link UnitIndependentBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is not
+	 *                                  supported.
+	 * @see SequenceRepresentation#IMPLICIT_LINEAR
+	 */
+	public UnitIndependentBuilder implicitLinear(ScalarType scalarType, double start, double increment) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.IMPLICIT_LINEAR);
+
+		Object values;
+		if (scalarType.isByte()) {
+			values = new byte[] { (byte) start, (byte) increment };
+		} else if (scalarType.isShort()) {
+			values = new short[] { (short) start, (short) increment };
+		} else if (scalarType.isInteger()) {
+			values = new int[] { (int) start, (int) increment };
+		} else if (scalarType.isLong()) {
+			values = new long[] { (long) start, (long) increment };
+		} else if (scalarType.isFloat()) {
+			values = new float[] { (float) start, (float) increment };
+		} else if (scalarType.isDouble()) {
+			values = new double[] { start, increment };
+		} else {
+			throw new IllegalArgumentException("Scalar type '" + scalarType + "' is not supported.");
+		}
+		createValues(scalarType, values);
+
+		return new UnitIndependentBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create an implicit saw sequence of
+	 * measured values. An implicit sequence allows only numerical
+	 * {@link ScalarType}s as listed below:
+	 *
+	 * <ul>
+	 * <li>{@link ScalarType#BYTE}</li>
+	 * <li>{@link ScalarType#SHORT}</li>
+	 * <li>{@link ScalarType#INTEGER}</li>
+	 * <li>{@link ScalarType#LONG}</li>
+	 * <li>{@link ScalarType#FLOAT}</li>
+	 * <li>{@link ScalarType#DOUBLE}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> Given start, increment and valuesPerSaw will be cast to an
+	 * assignment compatible type.
+	 *
+	 * @param scalarType   The {@code ScalarType} of each single measured value in
+	 *                     the sequence.
+	 * @param start        The start value of each saw cycle.
+	 * @param increment    The increment.
+	 * @param valuesPerSaw The number of values per saw.
+	 * @return An {@link UnitBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is not
+	 *                                  supported.
+	 * @see SequenceRepresentation#IMPLICIT_SAW
+	 */
+	public UnitBuilder implicitSaw(ScalarType scalarType, double start, double increment, double valuesPerSaw) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.IMPLICIT_SAW);
+
+		Object values;
+		if (scalarType.isByte()) {
+			values = new byte[] { (byte) start, (byte) increment, (byte) valuesPerSaw };
+		} else if (scalarType.isShort()) {
+			values = new short[] { (short) start, (short) increment, (short) valuesPerSaw };
+		} else if (scalarType.isInteger()) {
+			values = new int[] { (int) start, (int) increment, (int) valuesPerSaw };
+		} else if (scalarType.isLong()) {
+			values = new long[] { (long) start, (long) increment, (long) valuesPerSaw };
+		} else if (scalarType.isFloat()) {
+			values = new float[] { (float) start, (float) increment, (float) valuesPerSaw };
+		} else if (scalarType.isDouble()) {
+			values = new double[] { start, increment, valuesPerSaw };
+		} else {
+			throw new IllegalArgumentException("Scalar type '" + scalarType + "' is not supported.");
+		}
+		createValues(scalarType, values);
+
+		// NOTE: if it ever should be required to make a channel of this type
+		// an independent one, then return an UnitIndependentBuilder instead!
+		return new UnitBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create a raw linear sequence of
+	 * measured values.
+	 *
+	 * @param offset The offset for each value.
+	 * @param factor The factor for each value.
+	 * @return A {@link ComplexNumericalValuesBuilder} is returned.
+	 * @see SequenceRepresentation#RAW_LINEAR
+	 */
+	public ComplexNumericalValuesBuilder rawLinear(double offset, double factor) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.RAW_LINEAR);
+		getWriteRequest().setGenerationParameters(new double[] { offset, factor });
+		return new ComplexNumericalValuesBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create a raw polynomial sequence of
+	 * measured values.
+	 *
+	 * @param coefficients At least 2 coefficients must be provided.
+	 * @return A {@link ComplexNumericalValuesBuilder} is returned.
+	 * @throws IllegalArgumentException Thrown if coefficients are missing or their
+	 *                                  length is less than 2.
+	 * @see SequenceRepresentation#RAW_POLYNOMIAL
+	 */
+	public ComplexNumericalValuesBuilder rawPolynomial(double... coefficients) {
+		if (coefficients == null || coefficients.length < 2) {
+			throw new IllegalArgumentException(
+					"Coefficients either missing or their length is " + "inconsitent with given grade");
+		}
+
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.RAW_POLYNOMIAL);
+
+		double[] generationParameters = new double[coefficients.length + 1];
+		generationParameters[0] = coefficients.length - 1;
+		System.arraycopy(coefficients, 0, generationParameters, 1, coefficients.length);
+		getWriteRequest().setGenerationParameters(generationParameters);
+
+		// TODO: currently it is possible to define such a channel as
+		// independent
+		// should we prevent this?!
+		return new ComplexNumericalValuesBuilder(getWriteRequest());
+	}
+
+	/**
+	 * Configures the {@link WriteRequest} to create a raw linear calibrated
+	 * sequence of measured values.
+	 *
+	 * @param offset      The offset for each value.
+	 * @param factor      The factor for each value.
+	 * @param calibration The calibration factor.
+	 * @return A {@link ComplexNumericalValuesBuilder} is returned.
+	 * @see SequenceRepresentation#RAW_LINEAR_CALIBRATED
+	 */
+	public ComplexNumericalValuesBuilder rawLinearCalibrated(double offset, double factor, double calibration) {
+		getWriteRequest().setSequenceRepresentation(SequenceRepresentation.RAW_LINEAR_CALIBRATED);
+		getWriteRequest().setGenerationParameters(new double[] { offset, factor, calibration });
+		return new ComplexNumericalValuesBuilder(getWriteRequest());
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestFinalizer.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestFinalizer.java
new file mode 100644
index 0000000..0e57e9f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/massdata/WriteRequestFinalizer.java
@@ -0,0 +1,72 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.massdata;
+
+/**
+ * This class provides a terminal {@link WriteRequest} build operation to
+ * retrieve the configured {@code WriteRequest}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class WriteRequestFinalizer {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final WriteRequest writeRequest;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param writeRequest The configured {@link WriteRequest}.
+	 */
+	WriteRequestFinalizer(WriteRequest writeRequest) {
+		this.writeRequest = writeRequest;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the configured {@link WriteRequest}.
+	 *
+	 * @return The configured {@code WriteRequest} is returned.
+	 */
+	public final WriteRequest build() {
+		return getWriteRequest();
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link WriteRequest}.
+	 *
+	 * @return The {@code WriteRequest} is returned.
+	 */
+	protected final WriteRequest getWriteRequest() {
+		return writeRequest;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/AxisType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/AxisType.java
new file mode 100644
index 0000000..913590d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/AxisType.java
@@ -0,0 +1,80 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This is the axis type enumeration as defined in the ASAM ODS NVH model.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Channel
+ */
+public class AxisType extends EnumerationValue {
+
+	/**
+	 * A {@link Channel} of this type may be displayed as the x-axis.
+	 */
+	public static final AxisType X_AXIS = new AxisType("X_AXIS", 0);
+
+	/**
+	 * A {@link Channel} of this type may be displayed as the y-axis.
+	 */
+	public static final AxisType Y_AXIS = new AxisType("Y_AXIS", 1);
+
+	/**
+	 * A {@link Channel} of this type may be displayed as the x- or y-axis.
+	 */
+	public static final AxisType XY_AXIS = new AxisType("XY_AXIS", 2);
+
+	private AxisType(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns true if this axis type is {@link #X_AXIS}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isXAxis() {
+		return X_AXIS == this;
+	}
+
+	/**
+	 * Returns true if this axis type is {@link #Y_AXIS}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isYAxis() {
+		return Y_AXIS == this;
+	}
+
+	/**
+	 * Returns true if this axis type is {@link #XY_AXIS}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isXYAxis() {
+		return XY_AXIS == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntity.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntity.java
new file mode 100644
index 0000000..7211a23
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntity.java
@@ -0,0 +1,134 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * This is a base implementation for modeled entities. API consumers should
+ * never use this class in any way, instead the most common interface should be
+ * used (e.g.: {@link Entity}, {@link ContextDescribable}, etc.). API producers
+ * must let their {@code Entity} implementations extend this class.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public abstract class BaseEntity implements Entity {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Core core;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	protected BaseEntity(Core core) {
+		this.core = core;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getSourceName() {
+		return getCore().getSourceName();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getTypeName() {
+		return getCore().getTypeName();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String getID() {
+		return getCore().getID();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final Value getValue(String name) {
+		Value value = getCore().getValues().get(name);
+		if (value == null) {
+			throw new IllegalStateException("Value with name '" + name + "' does not exist");
+		}
+		return value;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final Map<String, Value> getValues() {
+		return Collections.unmodifiableMap(getCore().getValues());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		String prefix = new StringBuilder(getClass().getSimpleName()).append('(').toString();
+		return getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ", prefix, ")"));
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Returns the internally stored {@link Core}.
+	 *
+	 * @return The {@link Core} is returned.
+	 */
+	protected Core getCore() {
+		return core;
+	}
+
+	/**
+	 * Convenience method to extract {@link Core} of given {@link Entity}.
+	 *
+	 * @param entity The {@code Entity} whose {@code Core} is required.
+	 * @return The {@code Core} is returned.
+	 */
+	protected static Core getCore(Entity entity) {
+		return ((BaseEntity) entity).getCore();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java
new file mode 100644
index 0000000..fbf75a2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseEntityFactory.java
@@ -0,0 +1,564 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+
+/**
+ * Implementation of an abstract entity factory which creates new entities.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public abstract class BaseEntityFactory {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link Channel}. The name of the returned {@code Channel} is
+	 * retrieved from given {@link Quantity}.
+	 *
+	 * @param measurement The parent {@link Measurement}.
+	 * @param quantity    The {@code Quantity} is used for default initialization.
+	 * @return The created {@code Channel} is returned.
+	 */
+	public Channel createChannel(Measurement measurement, Quantity quantity) {
+		return createChannel(quantity.getDefaultChannelName(), measurement, quantity);
+	}
+
+	/**
+	 * Creates a new {@link Channel}.
+	 *
+	 * @param name        Name of the created {@code Channel}.
+	 * @param measurement The parent {@link Measurement}.
+	 * @param quantity    The {@code Quantity} is used for default initialization.
+	 * @return The created {@code Channel} is returned.
+	 */
+	public Channel createChannel(String name, Measurement measurement, Quantity quantity) {
+		Channel channel = new Channel(createCore(Channel.class));
+
+		// relations
+		getCore(channel).getPermanentStore().set(measurement);
+		getCore(measurement).getChildrenStore().add(channel);
+		getCore(channel).getMutableStore().set(quantity.getDefaultUnit());
+		getCore(channel).getMutableStore().set(quantity);
+
+		// properties
+		channel.setName(name);
+		channel.setDescription(quantity.getDescription());
+		channel.setInterpolation(Interpolation.NONE);
+		channel.setScalarType(quantity.getDefaultScalarType());
+		channel.setRank(quantity.getDefaultRank());
+		channel.setTypeSize(quantity.getDefaultTypeSize());
+
+		return channel;
+	}
+
+	/**
+	 * Creates a new {@link ChannelGroup}.
+	 *
+	 * @param name           Name of the created {@code ChannelGroup}.
+	 * @param numberOfValues The number of values per each related {@link Channel}.
+	 * @param measurement    The parent {@link Measurement}.
+	 * @return The created {@code ChannelGroup} is returned.
+	 * @throws IllegalArgumentException Thrown if numberOfValues is negative.
+	 */
+	public ChannelGroup createChannelGroup(String name, int numberOfValues, Measurement measurement) {
+		if (numberOfValues < 0) {
+			throw new IllegalArgumentException("Number of values must be equal or greater than 0.");
+		}
+
+		ChannelGroup channelGroup = new ChannelGroup(createCore(ChannelGroup.class));
+
+		// relations
+		getCore(channelGroup).getPermanentStore().set(measurement);
+		getCore(measurement).getChildrenStore().add(channelGroup);
+
+		// properties
+		channelGroup.setName(name);
+		channelGroup.setNumberOfValues(Integer.valueOf(numberOfValues));
+
+		return channelGroup;
+	}
+
+	/**
+	 * Creates a new {@link Measurement}.
+	 *
+	 * @param name         Name of the created {@code Measurement}.
+	 * @param testStep     The parent {@link TestStep}.
+	 * @param contextRoots {@link ContextRoot}s containing the descriptive data.
+	 * @return The created {@code Measurement} is returned.
+	 */
+	public Measurement createMeasurement(String name, TestStep testStep, ContextRoot... contextRoots) {
+		Measurement measurement = new Measurement(createCore(Measurement.class));
+
+		// relations
+		getCore(measurement).getPermanentStore().set(testStep);
+		getCore(testStep).getChildrenStore().add(measurement);
+		for (ContextRoot contextRoot : contextRoots) {
+			getCore(measurement).getMutableStore().set(contextRoot, contextRoot.getContextType());
+		}
+
+		// properties
+		measurement.setName(name);
+		measurement.setDateCreated(LocalDateTime.now());
+
+		return measurement;
+	}
+
+	/**
+	 * Creates a new {@link Parameter} with initialized with given value.
+	 *
+	 * @param name         Name of the created {@code Parameter}.
+	 * @param value        The value of the created {@code Parameter}.
+	 * @param unit         An optionally related {@link Unit}.
+	 * @param parameterSet The parent {@link ParameterSet}.
+	 * @return The created {@code Parameter} is returned.
+	 * @throws IllegalArgumentException Thrown if the {@code ParameterSet} already
+	 *                                  contains a {@code Parameter} with given
+	 *                                  name.
+	 * @see Parameter#setObjectValue(Object, Unit)
+	 */
+	public Parameter createParameter(String name, Object value, Unit unit, ParameterSet parameterSet) {
+		if (parameterSet.getParameter(name).isPresent()) {
+			throw new IllegalArgumentException("Parameter with name '" + name + "' already exists.");
+		}
+
+		Parameter parameter = new Parameter(createCore(Parameter.class));
+
+		// relations
+		getCore(parameter).getPermanentStore().set(parameterSet);
+		getCore(parameterSet).getChildrenStore().add(parameter);
+
+		// properties
+		parameter.setName(name);
+		parameter.setObjectValue(value, unit);
+
+		return parameter;
+	}
+
+	/**
+	 * Creates a new {@link ParameterSet} for given {@link Measurement}.
+	 *
+	 * @param name        Name of the created {@code ParameterSet}.
+	 * @param version     Version of the created {@code ParameterSet}.
+	 * @param measurement The owning {@code Measurement}.
+	 * @return The created {@code ParameterSet} is returned.
+	 */
+	public ParameterSet createParameterSet(String name, String version, Measurement measurement) {
+		ParameterSet parameterSet = new ParameterSet(createCore(ParameterSet.class));
+
+		// relations
+		getCore(parameterSet).getPermanentStore().set(measurement);
+		getCore(measurement).getChildrenStore().add(parameterSet);
+
+		// properties
+		parameterSet.setName(name);
+		parameterSet.setVersion(version);
+
+		return parameterSet;
+	}
+
+	/**
+	 * Creates a new {@link ParameterSet} for given {@link Channel}.
+	 *
+	 * @param name    Name of the created {@code ParameterSet}.
+	 * @param version Version of the created {@code ParameterSet}.
+	 * @param channel The owning {@code Channel}.
+	 * @return The created {@code ParameterSet} is returned.
+	 */
+	public ParameterSet createParameterSet(String name, String version, Channel channel) {
+		ParameterSet parameterSet = new ParameterSet(createCore(ParameterSet.class));
+
+		// relations
+		getCore(parameterSet).getPermanentStore().set(channel);
+		getCore(channel).getChildrenStore().add(parameterSet);
+
+		// properties
+		parameterSet.setName(name);
+		parameterSet.setVersion(version);
+
+		return parameterSet;
+	}
+
+	/**
+	 * Creates a new {@link PhysicalDimension}.
+	 *
+	 * @param name Name of the created {@code PhysicalDimension}.
+	 * @return The created {@code PhysicalDimension} is returned.
+	 */
+	public PhysicalDimension createPhysicalDimension(String name) {
+		PhysicalDimension physicalDimension = new PhysicalDimension(createCore(PhysicalDimension.class));
+
+		// properties
+		physicalDimension.setName(name);
+		physicalDimension.setLength(Integer.valueOf(0));
+		physicalDimension.setMass(Integer.valueOf(0));
+		physicalDimension.setTime(Integer.valueOf(0));
+		physicalDimension.setTemperature(Integer.valueOf(0));
+		physicalDimension.setCurrent(Integer.valueOf(0));
+		physicalDimension.setMolarAmount(Integer.valueOf(0));
+		physicalDimension.setLuminousIntensity(Integer.valueOf(0));
+		physicalDimension.setAngle(Integer.valueOf(0));
+
+		return physicalDimension;
+	}
+
+	/**
+	 * Creates a new {@link Quantity}.
+	 *
+	 * @param name        Name of the created {@code Quantity}.
+	 * @param defaultUnit The default {@link Unit}.
+	 * @return The created {@code Quantity} is returned.
+	 */
+	public Quantity createQuantity(String name, Unit defaultUnit) {
+		Quantity quantity = new Quantity(createCore(Quantity.class));
+
+		// relations
+		getCore(quantity).getMutableStore().set(defaultUnit);
+
+		// properties
+		quantity.setName(name);
+		quantity.setDateCreated(LocalDateTime.now());
+		quantity.setDefaultRank(Integer.valueOf(1));
+		quantity.setDefaultDimension(new int[] { 0 });
+		quantity.setDefaultTypeSize(Integer.valueOf(1));
+		quantity.setDefaultChannelName(name);
+		quantity.setDefaultScalarType(ScalarType.FLOAT);
+
+		quantity.getValue("Version").set("1");
+		quantity.getValue("ValidFlag").set(VersionState.VALID);
+
+		return quantity;
+	}
+
+	/**
+	 * Creates a new {@link Test} with a reference to the logged in {@link User}, if
+	 * there is one.
+	 *
+	 * @param name Name of the created {@code Test}.
+	 * @return The created {@code Test} is returned.
+	 */
+	public Test createTest(String name) {
+		Test test = new Test(createCore(Test.class));
+
+		// relations
+		Optional<User> responsiblePerson = getLoggedInUser();
+		if (responsiblePerson.isPresent()) {
+			// may be null if user entities are not available
+			getCore(test).getMutableStore().set(responsiblePerson.get());
+		}
+
+		// properties
+		test.setName(name);
+		test.setDateCreated(LocalDateTime.now());
+
+		return test;
+	}
+
+	/**
+	 * Creates a new {@link TestStep}.
+	 *
+	 * @param name Name of the created {@code TestStep}.
+	 * @param test The parent {@link Test}.
+	 * @return The created {@code TestStep} is returned.
+	 */
+	public TestStep createTestStep(String name, Test test) {
+		TestStep testStep = new TestStep(createCore(TestStep.class));
+
+		// relations
+		getCore(testStep).getPermanentStore().set(test);
+		getCore(test).getChildrenStore().add(testStep);
+
+		// properties
+		testStep.setName(name);
+		testStep.setDateCreated(LocalDateTime.now());
+		testStep.setOptional(Boolean.TRUE);
+
+		if (test.getID() != null && test.getID().length() > 0) {
+			// highest sort index in use will be queried before written
+			testStep.setSortIndex(Integer.valueOf(-1));
+		} else {
+			testStep.setSortIndex(nextIndex(getCore(test).getChildrenStore().get(TestStep.class)));
+		}
+
+		return testStep;
+	}
+
+	/**
+	 * Creates a new {@link Unit}.
+	 *
+	 * @param name              Name of the created {@code Unit}.
+	 * @param physicalDimension The {@link PhysicalDimension}.
+	 * @return The created {@code Unit} is returned.
+	 */
+	public Unit createUnit(String name, PhysicalDimension physicalDimension) {
+		Unit unit = new Unit(createCore(Unit.class));
+
+		// relations
+		getCore(unit).getMutableStore().set(physicalDimension);
+
+		// properties
+		unit.setName(name);
+		unit.setOffset(Double.valueOf(0D));
+		unit.setFactor(Double.valueOf(1D));
+
+		return unit;
+	}
+
+	/**
+	 * Creates a new {@link User}.
+	 *
+	 * @param name      Name of the created {@code User}.
+	 * @param givenName Given name of the created {@code User}.
+	 * @param surname   Surname of the created {@code User}.
+	 * @return The created {@code User} is returned.
+	 */
+	public User createUser(String name, String givenName, String surname) {
+		User user = new User(createCore(User.class));
+
+		// properties
+		user.setName(name);
+		user.setGivenName(givenName);
+		user.setSurname(surname);
+
+		return user;
+	}
+
+	// ======================================================================
+	// Protected methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link ContextRoot}.
+	 *
+	 * @param name        Name of the created {@code ContextRoot}.
+	 * @param contextType {@link ContextType} of the created {@code ContextRoot}.
+	 * @return The created {@code ContextRoot} is returned.
+	 */
+	protected ContextRoot createContextRoot(String name, ContextType contextType) {
+		ContextRoot contextRoot = new ContextRoot(createCore(ContextRoot.class, contextType));
+
+		// properties
+		contextRoot.setName(name);
+		contextRoot.setVersion(String.valueOf(0));
+
+		return contextRoot;
+	}
+
+	/**
+	 * Creates a new {@link ContextComponent}.
+	 *
+	 * @param name        Name of the created {@code ContextComponent}.
+	 * @param contextRoot The parent {@link ContextRoot}.
+	 * @return The created {@code ContextComponent} is returned.
+	 */
+	protected ContextComponent createContextComponent(String name, ContextRoot contextRoot) {
+		ContextComponent contextComponent = new ContextComponent(createCore(name, ContextComponent.class));
+
+		// relations
+		getCore(contextComponent).getPermanentStore().set(contextRoot);
+		getCore(contextRoot).getChildrenStore().add(contextComponent);
+
+		// properties
+		contextComponent.setName(name);
+
+		return contextComponent;
+	}
+
+	/**
+	 * Creates a new {@link ContextSensor}.
+	 *
+	 * @param name             Name of the created {@code ContextSensor}.
+	 * @param contextComponent The parent {@link ContextComponent}.
+	 * @return The created {@code ContextSensor} is returned.
+	 */
+	protected ContextSensor createContextSensor(String name, ContextComponent contextComponent) {
+		ContextSensor contextSensor = new ContextSensor(createCore(name, ContextSensor.class));
+		// relations
+		getCore(contextSensor).getPermanentStore().set(contextComponent);
+		getCore(contextComponent).getChildrenStore().add(contextSensor);
+
+		// properties
+		contextSensor.setName(name);
+
+		return contextSensor;
+	}
+
+	/**
+	 * Returns the next usable sort index for given {@code List} of
+	 * {@link Sortable}s.
+	 *
+	 * @param sortables The {@code Sortable} whose max sort index will be searched.
+	 * @return {@code 1} is returned if given {@code List} is empty, otherwise the
+	 *         max sort index increased by 1 is returned.
+	 */
+	protected static final Integer nextIndex(List<? extends Sortable> sortables) {
+		Optional<Integer> maxIndex = sortables.stream().max(Sortable.COMPARATOR).map(Sortable::getSortIndex);
+		return Integer.valueOf(maxIndex.isPresent() ? maxIndex.get().intValue() + 1 : 1);
+	}
+
+	/**
+	 * Returns the {@link ChildrenStore} for given {@link BaseEntity}. Please be
+	 * aware that the contents of this store is subject to the adapter creating it.
+	 * It is up to the adapter to decide which related entities are included. As
+	 * there are adapter specific details to the contents of the store it should be
+	 * protected from external access. Therefore by declaring this method protected,
+	 * the related functionality is hidden from other classes since the only classes
+	 * which can access them (outside this package) are derivatives of
+	 * BaseEntityFactory, and it is through such derivatives that BaseEntity's
+	 * Stores should be accessed elsewhere if needed.
+	 *
+	 * @param entity The {@code BaseEntity} whose {@code ChildrenStore} will be
+	 *               returned.
+	 * @return The {@code ChildrenStore} is returned.
+	 */
+	protected static ChildrenStore getChildrenStore(BaseEntity entity) {
+		return getCore(entity).getChildrenStore();
+	}
+
+	/**
+	 * Returns the mutable {@link EntityStore} for given {@link BaseEntity}. Please
+	 * be aware that the contents of this store is subject to the adapter creating
+	 * it. It is up to the adapter to decide which related entities are included. As
+	 * there are adapter specific details to the contents of the store it should be
+	 * protected from external access. Therefore by declaring this method protected,
+	 * the related functionality is hidden from other classes since the only classes
+	 * which can access them (outside this package) are derivatives of
+	 * BaseEntityFactory, and it is through such derivatives that BaseEntity's
+	 * Stores should be accessed elsewhere if needed.
+	 * 
+	 *
+	 * @param entity The {@code BaseEntity} whose {@code ChildrenStore} will be
+	 *               returned.
+	 * @return The mutable {@code EntityStore} is returned.
+	 */
+	protected static EntityStore getMutableStore(BaseEntity entity) {
+		return getCore(entity).getMutableStore();
+	}
+
+	/**
+	 * Returns the permanent {@link EntityStore} for given {@link BaseEntity}.
+	 * Please be aware that the contents of this store is subject to the adapter
+	 * creating it. It is up to the adapter to decide which related entities are
+	 * included. As there are adapter specific details to the contents of the store
+	 * it should be protected from external access. Therefore by declaring this
+	 * method protected, the related functionality is hidden from other classes
+	 * since the only classes which can access them (outside this package) are
+	 * derivatives of BaseEntityFactory, and it is through such derivatives that
+	 * BaseEntity's Stores should be accessed elsewhere if needed.
+	 * 
+	 * @param entity The {@code BaseEntity} whose {@code ChildrenStore} will be
+	 *               returned.
+	 * @return The permanent {@code EntityStore} is returned.
+	 */
+	protected static EntityStore getPermanentStore(BaseEntity entity) {
+		return getCore(entity).getPermanentStore();
+	}
+
+	/**
+	 * Returns {@link Core} of given {@link Entity}. Uses protected method from
+	 * BaseEntity, which is accessible here as BaseEntity resides in the same
+	 * package as BaseEntityFactory. By declaring this method protected, the
+	 * Core-related functionality is hidden from other classes since the only
+	 * classes which can access them (outside this package) are derivatives of
+	 * BaseEntityFactory, and it is through such derivatives that a BaseEntity's
+	 * Core should be accessed elsewhere if needed.
+	 *
+	 * @param entity The {@code BaseEntity} whose {@code Core} is required.
+	 * @return The {@code Core} is returned.
+	 */
+	protected static final Core getCore(BaseEntity entity) {
+		return entity.getCore();
+	}
+
+	/**
+	 * Create an instance of {@link BaseEntity} (or derivative) with core as the
+	 * instance's {@link Core}. By declaring this method protected, the Core-related
+	 * functionality is hidden from other classes since the only classes which can
+	 * access them (outside this package) are derivatives of BaseEntityFactory, and
+	 * it is through such derivatives that a BaseEntity's Core should be accessed
+	 * elsewhere if needed. <br>
+	 * <br>
+	 * This method accesses the (usually protected) Constructor(Core) of clazz, so
+	 * this method should be overridden in a derived class and call
+	 * super.createBaseEntity() if that constructor is invisible from the derived
+	 * class.
+	 * 
+	 * @param clazz The class to instantiate, must extend {@link BaseEntity}.
+	 * @param core  The {@link Core} to use for the newly created instance.
+	 * @return The newly created instance.
+	 */
+	protected <T extends BaseEntity> T createBaseEntity(Class<T> clazz, Core core) {
+		try {
+			Constructor<T> constructor = clazz.getDeclaredConstructor(Core.class);
+			try {
+				return constructor.newInstance(core);
+			} catch (IllegalAccessException exc) {
+				throw new IllegalStateException("Cannot access Constructor(Core) of class '" + clazz.getName() + "'!");
+			}
+		} catch (NoSuchMethodException | InvocationTargetException | InstantiationException exc) {
+			throw new IllegalStateException(exc.getMessage(), exc);
+		}
+	}
+
+	/**
+	 * Returns the {@link User} which is bound to the current session.
+	 *
+	 * @return {@code Optional} is empty if {@code User} entities do not exist.
+	 */
+	protected abstract Optional<User> getLoggedInUser();
+
+	/**
+	 * Returns a new {@link Core} for given entity class.
+	 *
+	 * @param <T>         The entity class type.
+	 * @param entityClass The entity class.
+	 * @return A new {@code Core} instance is returned.
+	 */
+	protected abstract <T extends Entity> Core createCore(Class<T> entityClass);
+
+	/**
+	 * Returns a new {@link Core} for given entity class and {@link ContextType}.
+	 *
+	 * @param <T>         The entity class type.
+	 * @param entityClass The entity class.
+	 * @param contextType The {@code ContextType}.
+	 * @return A new {@code Core} instance is returned.
+	 */
+	protected abstract <T extends Entity> Core createCore(Class<T> entityClass, ContextType contextType);
+
+	/**
+	 * Returns a new {@link Core} for given entity class and type name.
+	 *
+	 * @param <T>         The entity class type.
+	 * @param name        Name of the entity type.
+	 * @param entityClass The entity class.
+	 * @return A new {@code Core} instance is returned.
+	 */
+	protected abstract <T extends Entity> Core createCore(String name, Class<T> entityClass);
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseParameter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseParameter.java
new file mode 100644
index 0000000..21ab70f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/BaseParameter.java
@@ -0,0 +1,443 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of an abstract parameter which holds a value with one of the
+ * supported {@link ValueType}s listed below. The value is internally stored in
+ * its {@code String} representation. Any modeled entity with such a use case
+ * should extends this class. API consumers should never use this class in any
+ * way, instead the implementations of this class have to be used.
+ *
+ * <ul>
+ * <li>{@link ValueType#STRING}</li>
+ * <li>{@link ValueType#DATE}</li>
+ * <li>{@link ValueType#BOOLEAN}</li>
+ * <li>{@link ValueType#BYTE}</li>
+ * <li>{@link ValueType#SHORT}</li>
+ * <li>{@link ValueType#INTEGER}</li>
+ * <li>{@link ValueType#LONG}</li>
+ * <li>{@link ValueType#FLOAT}</li>
+ * <li>{@link ValueType#DOUBLE}</li>
+ * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+ * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see #getVirtualValue()
+ * @see #setObjectValue(Object, Unit)
+ * @see #setStringValue(String)
+ * @see #setDateValue(LocalDateTime)
+ * @see #setBooleanValue(Boolean)
+ * @see #setByteValue(Byte, Unit)
+ * @see #setShortValue(Short, Unit)
+ * @see #setIntegerValue(Integer, Unit)
+ * @see #setLongValue(Long, Unit)
+ * @see #setFloatValue(Float, Unit)
+ * @see #setDoubleValue(Double, Unit)
+ * @see #setFloatComplexValue(FloatComplex, Unit)
+ * @see #setDoubleComplexValue(DoubleComplex, Unit)
+ */
+public abstract class BaseParameter extends BaseEntity implements Deletable {
+
+	private static final Map<ScalarType, Function<String, Object>> SCALARTYPE_FUNCTION_MAP = new HashMap<>();
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final String attrScalarType;
+	private final String attrValue;
+
+	static {
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.STRING, v -> v);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.DATE, v -> LocalDateTime.parse(v, Value.LOCAL_DATE_TIME_FORMATTER));
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.BOOLEAN, Boolean::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.BYTE, Byte::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.SHORT, Short::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.INTEGER, Integer::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.LONG, Long::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.FLOAT, Float::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.DOUBLE, Double::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.FLOAT_COMPLEX, FloatComplex::valueOf);
+		SCALARTYPE_FUNCTION_MAP.put(ScalarType.DOUBLE_COMPLEX, DoubleComplex::valueOf);
+	}
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param attrScalarType Name of the {@link ScalarType} attribute.
+	 * @param attrValue      Name of the {@code String} value attribute.
+	 * @param core           The {@link Core}.
+	 */
+	protected BaseParameter(String attrScalarType, String attrValue, Core core) {
+		super(core);
+		this.attrScalarType = attrScalarType;
+		this.attrValue = attrValue;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a virtual representation of this parameter's value. This is done by
+	 * converting the internally stored {@code String} value to type specified by
+	 * this parameter's {@link ValueType} (the allowed types are listed below). The
+	 * name of the returned virtual {@link Value} is the name of this parameter.
+	 *
+	 * <ul>
+	 * <li>{@link ValueType#STRING}</li>
+	 * <li>{@link ValueType#DATE}</li>
+	 * <li>{@link ValueType#BOOLEAN}</li>
+	 * <li>{@link ValueType#BYTE}</li>
+	 * <li>{@link ValueType#SHORT}</li>
+	 * <li>{@link ValueType#INTEGER}</li>
+	 * <li>{@link ValueType#LONG}</li>
+	 * <li>{@link ValueType#FLOAT}</li>
+	 * <li>{@link ValueType#DOUBLE}</li>
+	 * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+	 * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+	 * </ul>
+	 *
+	 * <p>
+	 * <b>Note:</b> The returned value is a virtual one and hence intended for
+	 * displaying purposes only. To change this parameter's value one of its
+	 * {@code setXYValue} methods has to be used.
+	 *
+	 * @return The created {@code Value} with the converted value is returned.
+	 */
+	public Value getVirtualValue() {
+		ScalarType scalarType = getScalarType();
+		Function<String, Object> typeConverter = SCALARTYPE_FUNCTION_MAP.get(scalarType);
+
+		if (typeConverter == null) {
+			return ValueType.UNKNOWN.create(getName());
+		}
+
+		Value parameterValue = getParameterValue();
+		Object value = parameterValue.isValid() ? typeConverter.apply(parameterValue.extract()) : null;
+		return scalarType.toSingleValueType().create(getName(), getUnitName(), parameterValue.isValid(), value);
+	}
+
+	/**
+	 * Takes given value and determines its type. Finally value and the optional
+	 * {@code Unit} are passed to the corresponding {@code setXYValue(XY)} method as
+	 * listed below. The value is allowed to be an instance of the following types:
+	 * {@code String}, {@code LocalDateTime}, {@code Boolean}, {@code Byte},
+	 * {@code Short}, {@code Integer}, {@code Long}, {@code Float}, {@code Double},
+	 * {@code FloatComplex} and {@code DoubleComplex}.
+	 *
+	 * <p>
+	 * <b>Note:</b> If the given value is an instance of {@code String}, {@code
+	 * LocalDateTime} or a {@code Boolean}, then the given unit is ignored.
+	 *
+	 * @param value The new value for this parameter is not allowed to be null.
+	 * @param unit  The optionally related {@code Unit}.
+	 * @throws IllegalArgumentException Thrown if the given value is not supported.
+	 * @see #setStringValue(String)
+	 * @see #setDateValue(LocalDateTime)
+	 * @see #setBooleanValue(Boolean)
+	 * @see #setByteValue(Byte, Unit)
+	 * @see #setShortValue(Short, Unit)
+	 * @see #setIntegerValue(Integer, Unit)
+	 * @see #setLongValue(Long, Unit)
+	 * @see #setFloatValue(Float, Unit)
+	 * @see #setDoubleValue(Double, Unit)
+	 * @see #setFloatComplexValue(FloatComplex, Unit)
+	 * @see #setDoubleComplexValue(DoubleComplex, Unit)
+	 */
+	public void setObjectValue(Object value, Unit unit) {
+		if (value instanceof String) {
+			setStringValue((String) value);
+		} else if (value instanceof LocalDateTime) {
+			setDateValue((LocalDateTime) value);
+		} else if (value instanceof Boolean) {
+			setBooleanValue((Boolean) value);
+		} else if (value instanceof Byte) {
+			setByteValue((Byte) value, unit);
+		} else if (value instanceof Short) {
+			setShortValue((Short) value, unit);
+		} else if (value instanceof Integer) {
+			setIntegerValue((Integer) value, unit);
+		} else if (value instanceof Long) {
+			setLongValue((Long) value, unit);
+		} else if (value instanceof Float) {
+			setFloatValue((Float) value, unit);
+		} else if (value instanceof Double) {
+			setDoubleValue((Double) value, unit);
+		} else if (value instanceof FloatComplex) {
+			setFloatComplexValue((FloatComplex) value, unit);
+		} else if (value instanceof DoubleComplex) {
+			setDoubleComplexValue((DoubleComplex) value, unit);
+		} else {
+			throw new IllegalArgumentException(
+					"Value '" + value + "' of type '" + value.getClass().getSimpleName() + "' is not supported.");
+		}
+	}
+
+	/**
+	 * Replaces current value with given {@code String} value. Any existing relation
+	 * to a {@link Unit} will be removed.
+	 *
+	 * @param value The new value for this parameter.
+	 */
+	public void setStringValue(String value) {
+		setScalarType(ScalarType.STRING);
+		getParameterValue().set(value);
+		setUnit(null);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code LocalDateTime}. Any existing relation to a {@link Unit} will be
+	 * removed.
+	 *
+	 * @param value The new value for this parameter.
+	 */
+	public void setDateValue(LocalDateTime value) {
+		setScalarType(ScalarType.DATE);
+		getParameterValue().set(value.format(Value.LOCAL_DATE_TIME_FORMATTER));
+		setUnit(null);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Boolean}. Any existing relation to a {@link Unit} will be removed.
+	 *
+	 * @param value The new value for this parameter.
+	 */
+	public void setBooleanValue(Boolean value) {
+		setScalarType(ScalarType.BOOLEAN);
+		getParameterValue().set(value.toString());
+		setUnit(null);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Byte}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setByteValue(Byte value, Unit unit) {
+		setScalarType(ScalarType.BYTE);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Short}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setShortValue(Short value, Unit unit) {
+		setScalarType(ScalarType.SHORT);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Integer}. Any existing relation to a {@link Unit} will be replaced
+	 * with the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setIntegerValue(Integer value, Unit unit) {
+		setScalarType(ScalarType.INTEGER);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Long}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setLongValue(Long value, Unit unit) {
+		setScalarType(ScalarType.LONG);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Float}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setFloatValue(Float value, Unit unit) {
+		setScalarType(ScalarType.FLOAT);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code Double}. Any existing relation to a {@link Unit} will be replaced with
+	 * the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setDoubleValue(Double value, Unit unit) {
+		setScalarType(ScalarType.DOUBLE);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code FloatComplex}. Any existing relation to a {@link Unit} will be
+	 * replaced with the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setFloatComplexValue(FloatComplex value, Unit unit) {
+		setScalarType(ScalarType.FLOAT_COMPLEX);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * Replaces current value with the {@code String} representation of given
+	 * {@code DoubleComplex}. Any existing relation to a {@link Unit} will be
+	 * replaced with the given one.
+	 *
+	 * @param value The new value for this parameter.
+	 * @param unit  The relation to a unit is optional.
+	 */
+	public void setDoubleComplexValue(DoubleComplex value, Unit unit) {
+		setScalarType(ScalarType.DOUBLE_COMPLEX);
+		getParameterValue().set(value.toString());
+		setUnit(unit);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append("(Name = ").append(getName());
+
+		sb.append(", Value = ");
+		Value parameterValue = getParameterValue();
+		if (parameterValue.isValid()) {
+			sb.append((String) getParameterValue().extract());
+		}
+
+		Optional<Unit> unit = getUnit();
+		if (unit.isPresent()) {
+			sb.append(" [").append(unit.get().getName()).append(']');
+		}
+
+		return sb.append(')').toString();
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link Value} of this parameter.
+	 *
+	 * @return This parameter's {@code Value} is returned.
+	 */
+	private Value getParameterValue() {
+		return getValue(attrValue);
+	}
+
+	/**
+	 * Returns the scalar value type of this parameter.
+	 *
+	 * @return This parameter's scalar type is returned.
+	 */
+	private ScalarType getScalarType() {
+		return getValue(attrScalarType).extract();
+	}
+
+	/**
+	 * Sets new scalar type for this parameter.
+	 *
+	 * @param scalarType The new {@code ScalarType}.
+	 */
+	private void setScalarType(ScalarType scalarType) {
+		getValue(attrScalarType).set(scalarType);
+	}
+
+	/**
+	 * Returns the name of the related {@link Unit}. If no {@code Unit} is related,
+	 * an empty {@code String} is returned instead.
+	 *
+	 * @return The name of the related {@code Unit} is returned or an empty
+	 *         {@code String}.
+	 */
+	private String getUnitName() {
+		Optional<Unit> unit = getUnit();
+		if (unit.isPresent()) {
+			return unit.get().getName();
+		}
+
+		return "";
+	}
+
+	/**
+	 * Returns an optionally related {@link Unit}.
+	 *
+	 * @return The returned {@code Optional} is empty if no {@code Unit} is related.
+	 */
+	private Optional<Unit> getUnit() {
+		return Optional.ofNullable(getCore().getMutableStore().get(Unit.class));
+	}
+
+	/**
+	 * Replaces current {@link Unit} relation with the given one, if the {@code
+	 * Optional} is not empty. Otherwise any current relations is removed.
+	 *
+	 * @param unit The new {@code Unit} may be {@code null}.
+	 */
+	private void setUnit(Unit unit) {
+		if (unit == null) {
+			getCore().getMutableStore().remove(Unit.class);
+		} else {
+			getCore().getMutableStore().set(unit);
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Channel.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Channel.java
new file mode 100644
index 0000000..8391a79
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Channel.java
@@ -0,0 +1,279 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the channel entity type. Entities of this type are based on
+ * {@link Quantity}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Measurement
+ * @see ChannelGroup
+ * @see ContextSensor
+ * @see ParameterSet
+ */
+public class Channel extends BaseEntity implements Deletable, Describable {
+
+	// TODO Channel may have a relation to a sensor!
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Measurement} parent type.
+	 */
+	public static final Class<Measurement> PARENT_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The {@link ChannelGroup} parent type.
+	 */
+	public static final Class<ChannelGroup> PARENT_TYPE_CHANNELGROUP = ChannelGroup.class;
+
+	/**
+	 * The {@link ParameterSet} child type.
+	 */
+	public static final Class<ParameterSet> CHILD_TYPE_PARAMETERSET = ParameterSet.class;
+
+	/**
+	 * The 'Minimum' attribute name.
+	 */
+	public static final String ATTR_MINIMUM = "Minimum";
+
+	/**
+	 * The 'Maximum' attribute name.
+	 */
+	public static final String ATTR_MAXIMUM = "Maximum";
+
+	/**
+	 * The 'Average' attribute name.
+	 */
+	public static final String ATTR_AVERAGE = "Average";
+
+	/**
+	 * The 'Deviation' attribute name.
+	 */
+	public static final String ATTR_DEVIATION = "Deviation";
+
+	/**
+	 * The 'ScalarType' attribute name.
+	 */
+	public static final String ATTR_SCALAR_TYPE = "DataType";
+
+	/**
+	 * The 'Interpolation' attribute name.
+	 */
+	public static final String ATTR_INTERPOLATION = "Interpolation";
+
+	/**
+	 * The 'Rank' attribute name.
+	 */
+	public static final String ATTR_RANK = "Rank";
+
+	/**
+	 * The 'TypeSize' attribute name.
+	 */
+	public static final String ATTR_TYPE_SIZE = "TypeSize";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Channel(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the minimum value of this channel.
+	 *
+	 * @return The minimum value is returned.
+	 */
+	public Double getMinimum() {
+		return getValue(ATTR_MINIMUM).extract();
+	}
+
+	/**
+	 * Sets new minimum value for this channel.
+	 *
+	 * @param minimum The new minimum value.
+	 */
+	public void setMinimum(Double minimum) {
+		getValue(ATTR_MINIMUM).set(minimum);
+	}
+
+	/**
+	 * Returns the maximum value of this channel.
+	 *
+	 * @return The maximum value is returned.
+	 */
+	public Double getMaximum() {
+		return getValue(ATTR_MAXIMUM).extract();
+	}
+
+	/**
+	 * Sets new maximum value for this channel.
+	 *
+	 * @param maximum The new maximum value.
+	 */
+	public void setMaximum(Double maximum) {
+		getValue(ATTR_MAXIMUM).set(maximum);
+	}
+
+	/**
+	 * Returns the average value of this channel.
+	 *
+	 * @return The average value is returned.
+	 */
+	public Double getAverage() {
+		return getValue(ATTR_AVERAGE).extract();
+	}
+
+	/**
+	 * Sets new average value for this channel.
+	 *
+	 * @param average The new average value.
+	 */
+	public void setAverage(Double average) {
+		getValue(ATTR_AVERAGE).set(average);
+	}
+
+	/**
+	 * Returns the deviation value of this channel.
+	 *
+	 * @return The deviation value is returned.
+	 */
+	public Double getDeviation() {
+		return getValue(ATTR_DEVIATION).extract();
+	}
+
+	/**
+	 * Sets new deviation value for this channel.
+	 *
+	 * @param deviation The new deviation value.
+	 */
+	public void setDeviation(Double deviation) {
+		getValue(ATTR_DEVIATION).set(deviation);
+	}
+
+	/**
+	 * Returns the {@link ScalarType} of this channel.
+	 *
+	 * @return The {@code ScalarType} is returned.
+	 */
+	public ScalarType getScalarType() {
+		return getValue(ATTR_SCALAR_TYPE).extract();
+	}
+
+	/**
+	 * Sets new {@link ScalarType} for this channel.
+	 *
+	 * @param scalarType The new {@code ScalarType}.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is
+	 *                                  {@link ScalarType#UNKNOWN}.
+	 */
+	public void setScalarType(ScalarType scalarType) {
+		if (scalarType.isUnknown()) {
+			throw new IllegalArgumentException("Scalar type constant is not allowed to be '" + scalarType + "'.");
+		}
+
+		getValue(ATTR_SCALAR_TYPE).set(scalarType);
+	}
+
+	/**
+	 * Returns the {@link Interpolation} of this channel.
+	 *
+	 * @return The {@code Interpolation} is returned.
+	 */
+	public Interpolation getInterpolation() {
+		return getValue(ATTR_INTERPOLATION).extract();
+	}
+
+	/**
+	 * Sets new interpolation for this channel.
+	 *
+	 * @param interpolation The new {@code Interpolation}.
+	 */
+	public void setInterpolation(Interpolation interpolation) {
+		getValue(ATTR_INTERPOLATION).set(interpolation);
+	}
+
+	/**
+	 * Returns the rank of this channel.
+	 *
+	 * @return The rank is returned.
+	 */
+	public Integer getRank() {
+		return getValue(ATTR_RANK).extract();
+	}
+
+	/**
+	 * Sets new rank for this channel.
+	 *
+	 * @param rank The new rank.
+	 */
+	public void setRank(Integer rank) {
+		getValue(ATTR_RANK).set(rank);
+	}
+
+	/**
+	 * Returns the type size of this channel.
+	 *
+	 * @return The type size is returned.
+	 */
+	public Integer getTypeSize() {
+		return getValue(ATTR_TYPE_SIZE).extract();
+	}
+
+	/**
+	 * Sets new type size for this channel.
+	 *
+	 * @param typeSize The new type size.
+	 */
+	public void setTypeSize(Integer typeSize) {
+		getValue(ATTR_TYPE_SIZE).set(typeSize);
+	}
+
+	/**
+	 * Returns the related {@link Unit}.
+	 *
+	 * @return Related {@code Unit} is returned.
+	 */
+	public Unit getUnit() {
+		return getCore().getMutableStore().get(Unit.class);
+	}
+
+	/**
+	 * Returns the related {@link Quantity}.
+	 *
+	 * @return Related {@code Quantity} is returned.
+	 */
+	public Quantity getQuantity() {
+		return getCore().getMutableStore().get(Quantity.class);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ChannelGroup.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ChannelGroup.java
new file mode 100644
index 0000000..e906bdd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ChannelGroup.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the channel group entity type. It belongs to exactly one
+ * {@link Measurement} and groups a set of its {@link Channel}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ChannelGroup extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Measurement} parent type.
+	 */
+	public static final Class<Measurement> PARENT_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The {@link Channel} child type.
+	 */
+	public static final Class<Channel> CHILD_TYPE_CHANNEL = Channel.class;
+
+	/**
+	 * The 'NumberOfValues' attribute name.
+	 */
+	public static final String ATTR_NUMBER_OF_VALUES = "SubMatrixNoRows";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ChannelGroup(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the number of measured values of each related {@link Channel}.
+	 *
+	 * @return The number of measured values per {@code Channel} is returned.
+	 */
+	public Integer getNumberOfValues() {
+		return getValue(ATTR_NUMBER_OF_VALUES).extract();
+	}
+
+	/**
+	 * Sets new number of values for this channel group.
+	 *
+	 * @param numberOfValues The new number of values.
+	 */
+	public void setNumberOfValues(Integer numberOfValues) {
+		getValue(ATTR_NUMBER_OF_VALUES).set(numberOfValues);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextComponent.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextComponent.java
new file mode 100644
index 0000000..bbd3bec
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextComponent.java
@@ -0,0 +1,116 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the context component entity types. Instances of this class
+ * are only provided / managed via the owning descriptive {@link ContextRoot}.
+ * Additionally if the owning {@code ContextRoot} is of type
+ * {@link ContextType#TESTEQUIPMENT} this context component may have relations
+ * to {@link ContextSensor}s whose names have to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ContextComponent extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ContextComponent(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextSensor} identified by given name.
+	 *
+	 * @param name The name of the {@code ContextSensor}.
+	 * @return The {@code Optional} is empty if a {@code ContextSensor} with given
+	 *         name does not exist.
+	 */
+	public Optional<ContextSensor> getContextSensor(String name) {
+		return getContextSensors().stream().filter(cs -> cs.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link ContextSensor}s related to this context
+	 * component.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<ContextSensor> getContextSensors() {
+		return getCore().getChildrenStore().get(ContextSensor.class);
+	}
+
+	/**
+	 * Returns the {@link ContextRoot} this context component belongs to.
+	 *
+	 * @return The parent {@link ContextRoot}.
+	 */
+	public ContextRoot getContextRoot() {
+		return getCore().getPermanentStore().get(ContextRoot.class);
+	}
+
+	/**
+	 * Removes the {@link ContextSensor} identified by given name.
+	 *
+	 * @param name Name of the {@code ContextSensor} that has to be removed.
+	 * @return Returns {@code true} if the {@code ContextSensor} with given name has
+	 *         been removed.
+	 */
+	public boolean removeContextSensor(String name) {
+		Optional<ContextSensor> catalogSensor = getContextSensor(name);
+		if (catalogSensor.isPresent()) {
+			getCore().getChildrenStore().remove(catalogSensor.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<ContextSensor> contextSensors = getContextSensors();
+		if (!contextSensors.isEmpty()) {
+			sb.append(", ContextSensors = ").append(contextSensors);
+		}
+
+		return sb.append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextDescribable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextDescribable.java
new file mode 100644
index 0000000..9fea69a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextDescribable.java
@@ -0,0 +1,62 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * {@link TestStep} and {@link Measurement} entity types implement this
+ * interface to indicate the availability of descriptive context data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ContextRoot
+ * @see ContextComponent
+ * @see ContextSensor
+ */
+public interface ContextDescribable extends Entity {
+	/**
+	 * Queries available {@link ContextType} for given {@link ContextDescribable}.
+	 *
+	 * @param manager An object implementing BaseEntityManager.
+	 * @return {@code List} contains the {@code ContextType} of each referenced
+	 *         {@link ContextRoot}.
+	 * @throws DataAccessException Thrown if unable to query the available
+	 *                             {@code ContextType}s.
+	 */
+	List<ContextType> loadContextTypes(BaseEntityManager manager) throws DataAccessException;
+
+	/**
+	 * Loads the requested {@link ContextRoot}s for given
+	 * {@link ContextDescribable}.
+	 *
+	 * @param manager      An object implementing BaseEntityManager.
+	 * @param contextTypes The requested context types. If omitted, all types are be
+	 *                     loaded.
+	 * @return The ordered contexts for given {@code TestStep} or the measured ones
+	 *         for {@code Measurement} are returned in a {@code Map}.
+	 * @throws DataAccessException Thrown if unable to retrieve the {@code
+	 * 		ContextRoot}        s.
+	 * @see ContextType
+	 */
+	Map<ContextType, ContextRoot> loadContexts(BaseEntityManager manager, ContextType... contextTypes)
+			throws DataAccessException;
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextRoot.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextRoot.java
new file mode 100644
index 0000000..369e1fd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextRoot.java
@@ -0,0 +1,208 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the context root entity types. This is the root node of the
+ * descriptive component structure for a {@link ContextType}. This element is
+ * used for both, order and measured result description data. If it belongs to
+ * an order description, then a relation to a {@link TestStep} exists. Otherwise
+ * it represents the description of a measurement and therefore has one ore more
+ * relations to {@link Measurement}s. In the base application model the
+ * component structure is provided as is. An extension of the base application
+ * model may define a template, the structure of contained
+ * {@link ContextComponent}s and {@link ContextSensor}s will be restricted to.
+ * Additionally the <b>names</b> of all related {@code ContextComponent}s have
+ * to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ContextRoot extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Version' attribute name.
+	 */
+	public static final String ATTR_VERSION = "Version";
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ContextType contextType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ContextRoot(Core core) {
+		super(core);
+		contextType = ContextType.valueOf(core.getTypeName().toUpperCase(Locale.ROOT));
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextType} of this context root.
+	 *
+	 * @return The {@code ContextType} is returned.
+	 */
+	public ContextType getContextType() {
+		return contextType;
+	}
+
+	/**
+	 * Returns the {@link ContextComponent} identified by given name.
+	 *
+	 * @param name The name of the {@code ContextComponent}.
+	 * @return The {@code Optional} is empty if a {@code ContextComponent} with
+	 *         given name does not exist.
+	 */
+	public Optional<ContextComponent> getContextComponent(String name) {
+		return getContextComponents().stream().filter(cc -> cc.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link ContextComponent}s related to this context root.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<ContextComponent> getContextComponents() {
+		return getCore().getChildrenStore().get(ContextComponent.class);
+	}
+
+	/**
+	 * Removes the {@link ContextComponent} identified by given name.
+	 *
+	 * @param name Name of the {@code ContextComponent} that have to be removed.
+	 * @return Returns {@code true} if the {@code ContextComponent} with given name
+	 *         has been removed.
+	 */
+	public boolean removeContextComponent(String name) {
+		Optional<ContextComponent> contextComponent = getContextComponent(name);
+		if (contextComponent.isPresent()) {
+			getCore().getChildrenStore().remove(contextComponent.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns all available {@link ContextSensor}s related to the
+	 * {@link ContextComponent}s, which are held by this context root.
+	 *
+	 * @return The returned {@code List} will always be empty if this context root
+	 *         is of type {@link ContextType#UNITUNDERTEST} or
+	 *         {@link ContextType#TESTSEQUENCE}.
+	 */
+	public List<ContextSensor> getContextSensors() {
+		if (!getContextType().isTestEquipment()) {
+			return Collections.emptyList();
+		}
+
+		return getContextComponents().stream().map(ContextComponent::getContextSensors).collect(ArrayList::new,
+				List::addAll, List::addAll);
+	}
+
+	/**
+	 * Returns the version of this context root.
+	 *
+	 * @return The version is returned.
+	 */
+	public String getVersion() {
+		return getValue(ATTR_VERSION).extract();
+	}
+
+	/**
+	 * Sets new version for this context root.
+	 *
+	 * @param version The new version.
+	 */
+	public void setVersion(String version) {
+		getValue(ATTR_VERSION).set(version);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append("ContextType = ").append(getContextType()).append(", ");
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+
+		List<ContextComponent> contextComponents = getContextComponents();
+		if (!contextComponents.isEmpty()) {
+			sb.append(", ContextComponents = ").append(contextComponents);
+		}
+
+		return sb.append(')').toString();
+	}
+
+	/**
+	 * Convenience method to access the {@link ContextRoot}s of newly created
+	 * {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or a {@link Measurement}.
+	 * @return The {@code ContextRoot}s are returned.
+	 */
+	public static List<ContextRoot> of(ContextDescribable contextDescribable) {
+		List<ContextRoot> contextRoots = new ArrayList<>();
+		of(contextDescribable, ContextType.UNITUNDERTEST).ifPresent(contextRoots::add);
+		of(contextDescribable, ContextType.TESTSEQUENCE).ifPresent(contextRoots::add);
+		of(contextDescribable, ContextType.TESTEQUIPMENT).ifPresent(contextRoots::add);
+		return contextRoots;
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link ContextRoot} with given {@link ContextType} from given
+	 * {@link ContextDescribable}.
+	 *
+	 * @param contextDescribable Either a {@link TestStep} or a {@link Measurement}.
+	 * @param contextType        The requested {@code ContextType}.
+	 * @return {@code Optional} is empty if a {@code ContextRoot} with given
+	 *         {@code ContextType} does not exist.
+	 */
+	private static Optional<ContextRoot> of(ContextDescribable contextDescribable, ContextType contextType) {
+		return Optional.ofNullable(getCore(contextDescribable).getMutableStore().get(ContextRoot.class, contextType));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextSensor.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextSensor.java
new file mode 100644
index 0000000..7579c12
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextSensor.java
@@ -0,0 +1,51 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the context sensor entity types. Instances of this class
+ * are only provided / managed via the owning {@link ContextComponent}. A
+ * context sensor may be related to a {@link Channel}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ContextSensor extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ContextSensor(Core core) {
+		super(core);
+	}
+
+	/**
+	 * Returns the {@link ContextComponent} this context sensor belongs to.
+	 *
+	 * @return The parent {@link ContextComponent}
+	 */
+	public ContextComponent getContextComponent() {
+		return getCore().getPermanentStore().get(ContextComponent.class);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextType.java
new file mode 100644
index 0000000..98a3541
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ContextType.java
@@ -0,0 +1,81 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Context type enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ContextRoot
+ */
+public enum ContextType {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * A {@link ContextRoot} of this type unites meta data of the unit under test.
+	 */
+	UNITUNDERTEST,
+
+	/**
+	 * A {@link ContextRoot} of this type unites meta data of the test conditions.
+	 */
+	TESTSEQUENCE,
+
+	/**
+	 * A {@link ContextRoot} of this type unites meta data of the used equipment
+	 * (hardware and sensors).
+	 */
+	TESTEQUIPMENT;
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns true if this context type is {@link #UNITUNDERTEST}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isUnitUnderTest() {
+		return UNITUNDERTEST == this;
+	}
+
+	/**
+	 * Returns true if this context type is {@link #TESTSEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isTestSequence() {
+		return TESTSEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this context type is {@link #TESTEQUIPMENT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isTestEquipment() {
+		return TESTEQUIPMENT == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Datable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Datable.java
new file mode 100644
index 0000000..714dc74
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Datable.java
@@ -0,0 +1,60 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'DateCreated' field of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Datable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'DateCreated' attribute name.
+	 */
+	String ATTR_DATE_CREATED = "DateCreated";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the creation time stamp of this entity.
+	 *
+	 * @return The creation time stamp is returned.
+	 */
+	default LocalDateTime getDateCreated() {
+		return getValue(ATTR_DATE_CREATED).extract();
+	}
+
+	/**
+	 * Set new creation time stamp for this entity.
+	 *
+	 * @param dateCreated The new creation time stamp.
+	 */
+	default void setDateCreated(LocalDateTime dateCreated) {
+		getValue(ATTR_DATE_CREATED).set(dateCreated);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Deletable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Deletable.java
new file mode 100644
index 0000000..156d949
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Deletable.java
@@ -0,0 +1,27 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This interface is used to indicate that implementing entity types are allowed
+ * to be deleted.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Deletable extends Entity {
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Describable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Describable.java
new file mode 100644
index 0000000..0ea31f8
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Describable.java
@@ -0,0 +1,58 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'Description' field of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Describable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Description' attribute name.
+	 */
+	String ATTR_DESCRIPTION = "Description";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the description of this entity.
+	 *
+	 * @return The description is returned.
+	 */
+	default String getDescription() {
+		return getValue(ATTR_DESCRIPTION).extract();
+	}
+
+	/**
+	 * Sets new description for this entity.
+	 *
+	 * @param description The new description.
+	 */
+	default void setDescription(String description) {
+		getValue(ATTR_DESCRIPTION).set(description);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/DoubleComplex.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/DoubleComplex.java
new file mode 100644
index 0000000..c870ee2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/DoubleComplex.java
@@ -0,0 +1,100 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This class represents a complex value with real and imaginary parts of type
+ * {@code double}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class DoubleComplex {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final double re;
+	private final double im;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param real      The real part.
+	 * @param imaginary The imaginary part.
+	 */
+	public DoubleComplex(double real, double imaginary) {
+		re = real;
+		im = imaginary;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Parses given {@code String} where real and imaginary parts are separated by
+	 * one or more blanks. Furthermore both must be floating point numbers that can
+	 * be parsed by calling {@link Double#valueOf(String)}.
+	 *
+	 * @param s The {@code String} to be parsed.
+	 * @return The parsed {@link DoubleComplex} value is returned.
+	 * @throws NumberFormatException Thrown if unable to parse the complex value.
+	 */
+	public static DoubleComplex valueOf(String s) {
+		String[] values = s.split(" +");
+		if (values.length != 2) {
+			throw new NumberFormatException("Unable to parse complex value.");
+		}
+
+		return new DoubleComplex(Double.parseDouble(values[0]), Double.parseDouble(values[1]));
+	}
+
+	/**
+	 * Returns the real part of this complex value.
+	 *
+	 * @return The real part is returned.
+	 */
+	public double real() {
+		return re;
+	}
+
+	/**
+	 * Returns the imaginary part of this complex value.
+	 *
+	 * @return The imaginary part is returned.
+	 */
+	public double imaginary() {
+		return im;
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this complex value.
+	 * The real and imaginary parts are separated with a blank.
+	 *
+	 * @return The {@code String} representation of this complex value.
+	 */
+	@Override
+	public String toString() {
+		return new StringBuilder().append(real()).append(' ').append(imaginary()).toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Entity.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Entity.java
new file mode 100644
index 0000000..bd48e4f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Entity.java
@@ -0,0 +1,148 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Comparator;
+import java.util.Map;
+
+/**
+ * This is the base interface for any modeled entity type.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * This {@code Comparator} compares entities by their name in ascending order.
+	 */
+	Comparator<Entity> COMPARATOR = Comparator.comparing(Entity::getName);
+
+	/**
+	 * The 'MimeType' attribute name.
+	 */
+	String ATTR_MIMETYPE = "MimeType";
+
+	/**
+	 * The 'Name' attribute name.
+	 */
+	String ATTR_NAME = "Name";
+
+	/**
+	 * The 'Id' attribute name.
+	 */
+	String ATTR_ID = "Id";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of the data source this entity was retrieved from.
+	 *
+	 * @return Name of the data source.
+	 */
+	String getSourceName();
+
+	/**
+	 * Returns the name of the entity type.
+	 *
+	 * @return Name of the entity type is returned.
+	 */
+	String getTypeName();
+
+	/**
+	 * Returns the instance ID or {@code 0} if this instance is not yet persisted.
+	 *
+	 * @return The instance ID is returned.
+	 */
+	String getID();
+
+	/**
+	 * Returns the name of this entity.
+	 *
+	 * @return The name is returned.
+	 */
+	default String getName() {
+		return getValue(ATTR_NAME).extract();
+	}
+
+	/**
+	 * Sets new name for this entity.
+	 *
+	 * @param name The new name.
+	 */
+	default void setName(String name) {
+		getValue(ATTR_NAME).set(name);
+	}
+
+	/**
+	 * Returns the {@link MimeType} of this entity.
+	 *
+	 * @return The {@code MimeType} is returned.
+	 */
+	default MimeType getMimeType() {
+		return new MimeType(getValue(ATTR_MIMETYPE).extract());
+	}
+
+	/**
+	 * Sets new {@link MimeType} for this entity.
+	 *
+	 * @param mimeType The new {@code MimeType}.
+	 */
+	default void setMimeType(MimeType mimeType) {
+		getValue(ATTR_MIMETYPE).set(mimeType.toString());
+	}
+
+	/**
+	 * Returns the {@link Value} container associated with given name.
+	 *
+	 * @param name Name of the attribute.
+	 * @return The {@code Value} container is returned.
+	 */
+	Value getValue(String name);
+
+	/**
+	 * Returns <i>all</i> {@link Value} containers of this entity mapped by their
+	 * name (no matter a value is valid or not).
+	 *
+	 * @return Returned {@code Map} is unmodifiable.
+	 */
+	Map<String, Value> getValues();
+
+	/**
+	 * Returns a human readable {@code String} representation of this entity.
+	 *
+	 * @return The {@code String} representation of this entity.
+	 */
+	@Override
+	String toString();
+
+	/**
+	 * Checks whether given name equals the name of this entity.
+	 *
+	 * @param name The checked name.
+	 * @return Returns {@code true} if given name equals the name of this entity.
+	 */
+	default boolean nameEquals(String name) {
+		return getName().equals(name);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumRegistry.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumRegistry.java
new file mode 100644
index 0000000..1d5d56f
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumRegistry.java
@@ -0,0 +1,78 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This singleton class registers globally available enumerations.
+ *
+ */
+public final class EnumRegistry {
+
+	// singleton instance
+	private static final EnumRegistry instance = new EnumRegistry();
+
+	public static final String SCALAR_TYPE = "ScalarType";
+	public static final String INTERPOLATION = "Interpolation";
+	public static final String SEQUENCE_REPRESENTATION = "SequenceRepresentation";
+	public static final String TYPE_SPECIFICATION = "TypeSpecification";
+	public static final String VALUE_TYPE = "ValueType";
+	public static final String VERSION_STATE = "VersionState";
+	public static final String AXIS_TYPE = "AxisType";
+
+	private Map<String, Enumeration<? extends EnumerationValue>> enumerations;
+
+	/**
+	 * Constructor. Not called directly. Use getInstance() instead.
+	 */
+	private EnumRegistry() {
+		enumerations = new HashMap<>();
+		add(INTERPOLATION, new Enumeration<Interpolation>(Interpolation.class, INTERPOLATION));
+		add(SCALAR_TYPE, new Enumeration<ScalarType>(ScalarType.class, SCALAR_TYPE));
+		add(SEQUENCE_REPRESENTATION,
+				new Enumeration<SequenceRepresentation>(SequenceRepresentation.class, SEQUENCE_REPRESENTATION));
+		add(TYPE_SPECIFICATION, new Enumeration<TypeSpecification>(TypeSpecification.class, TYPE_SPECIFICATION));
+		add(VALUE_TYPE, new Enumeration<ValueType>(ValueType.class, VALUE_TYPE));
+		add(VERSION_STATE, new Enumeration<VersionState>(VersionState.class, VERSION_STATE));
+		add(AXIS_TYPE, new Enumeration<AxisType>(AxisType.class, AXIS_TYPE));
+	}
+
+	/**
+	 * adds a new enumeration to the registry
+	 * 
+	 * @param name        the name under which the enumeration can be accessed
+	 * @param enumeration the dynamic enumeration object
+	 */
+	public void add(String name, Enumeration<? extends EnumerationValue> enumeration) {
+		enumerations.put(name, enumeration);
+	}
+
+	/**
+	 * @param name the name of the registered enumeration
+	 * @return the dynamic enumeration object
+	 */
+	public Enumeration<?> get(String name) {
+		return enumerations.get(name);
+	}
+
+	/**
+	 * @return the instance of this singleton
+	 */
+	public static EnumRegistry getInstance() {
+		return instance;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Enumeration.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Enumeration.java
new file mode 100644
index 0000000..79bd4ad
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Enumeration.java
@@ -0,0 +1,151 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A class which dynamically bundles enumeration values
+ *
+ * @param <E>
+ */
+public class Enumeration<E extends EnumerationValue> {
+
+	private Map<String, E> values;
+
+	private Map<E, String> revvalues;
+
+	private Map<Integer, String> ordinals;
+
+	private Map<String, Integer> revordinals;
+
+	private int maxordinal;
+
+	private String name;
+
+	private Class<E> enumclass;
+
+	/**
+	 * Constructor. Static fields in the given enumclass of the same type are added
+	 * automatically as enum values. This way you can simply prefill the object with
+	 * static values.
+	 * 
+	 * @param enumclass the class of the enumeration values
+	 * @param name      the name of the enumeration bundle
+	 */
+	@SuppressWarnings("unchecked")
+	public Enumeration(Class<E> enumclass, String name) {
+		this.maxordinal = 0;
+		this.values = new HashMap<>();
+		this.revvalues = new HashMap<>();
+		this.ordinals = new HashMap<>();
+		this.revordinals = new HashMap<>();
+		this.name = name;
+		this.enumclass = enumclass;
+		java.lang.reflect.Field[] fields = enumclass.getFields();
+		for (Field field : fields) {
+			if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) // only
+																			// examine
+																			// static
+																			// fields
+			{
+				Object fieldObject;
+				try {
+					fieldObject = field.get(null);
+					if (!(enumclass.isInstance(fieldObject))) {
+						continue;
+					}
+				} catch (Exception e) {
+					throw new RuntimeException(e);
+				}
+				String fname = ((EnumerationValue) fieldObject).name();
+				if (fname == null) {
+					fname = field.getName();
+					((EnumerationValue) fieldObject).setName(fname);
+				}
+				addValue((E) fieldObject);
+			}
+		}
+	}
+
+	/**
+	 * adds a value to the dynamic enumeration
+	 * 
+	 * @param enumeration
+	 */
+	public void addValue(E enumeration) {
+		enumeration.setOwner(this);
+		String enumerationName = enumeration.name();
+		Integer ordinal = enumeration.ordinal();
+		if (ordinal == null) {
+			ordinal = ++maxordinal;
+			enumeration.setOrdinal(ordinal);
+		} else {
+			maxordinal = Math.max(ordinal, maxordinal);
+		}
+		values.put(enumerationName, enumeration);
+		revvalues.put(enumeration, enumerationName);
+		ordinals.put(ordinal, enumerationName);
+		revordinals.put(enumerationName, ordinal);
+	}
+
+	/**
+	 * returns the value represented by the given name
+	 * 
+	 * @param name
+	 * @return
+	 */
+	public E valueOf(String name) {
+		return values.get(name);
+	}
+
+	/**
+	 * returns the value represented by the given number
+	 * 
+	 * @param ordinal
+	 * @return
+	 */
+	public E valueOf(int ordinal) {
+		return values.get(ordinals.get(ordinal));
+	}
+
+	/**
+	 * returns the ordinal represented by the given enumeration value
+	 * 
+	 * @param enumval
+	 * @return
+	 */
+	public int ordinal(EnumerationValue enumval) {
+		return revordinals.get(revvalues.get(enumval));
+	}
+
+	/**
+	 * @return the class of the enumeration values represented by this dynamic
+	 *         enumeration
+	 */
+	public Class<E> getEnumClass() {
+		return enumclass;
+	}
+
+	/**
+	 * @return the name of the dynamic enumeration collection
+	 */
+	public String getName() {
+		return name;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumerationValue.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumerationValue.java
new file mode 100644
index 0000000..679d7c4
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/EnumerationValue.java
@@ -0,0 +1,135 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Objects;
+
+/**
+ * This class emulates the behaviour of a java enum. The reason for its
+ * existence is that classic enums can't be extended by new values. This class
+ * on the other hand can be extended by java's inheritance mechanism.
+ * 
+ * For a basic emulation of java enums, just extend this class and add static
+ * fields whose type is of the derivative class.
+ * 
+ * To be able to add dynamically enum values and for full initialization, you
+ * should set an owner enumeration (either by choosing the right constructor or
+ * by calling the setOwner method)
+ * 
+ * @author Florian Schmitt
+ *
+ */
+public class EnumerationValue {
+
+	private String name;
+	private Integer ordinal;
+
+	private Enumeration<? extends EnumerationValue> owner;
+
+	/**
+	 * explicitly set the name of this element.
+	 *
+	 * @param name
+	 */
+	protected void setName(String name) {
+		this.name = Objects.requireNonNull(name);
+	}
+
+	/**
+	 * explicitly set the ordinal of this element.
+	 */
+	protected void setOrdinal(int ordinal) {
+		this.ordinal = ordinal;
+	}
+
+	/**
+	 * 
+	 * set the owner dynamic enumeration of this object.
+	 * 
+	 * @param er
+	 */
+	protected void setOwner(Enumeration<? extends EnumerationValue> er) {
+		owner = er;
+	}
+
+	/**
+	 * get the owner dynamic enumeration of this object
+	 * 
+	 * @return
+	 */
+	public Enumeration<? extends EnumerationValue> getOwner() {
+		return owner;
+	}
+
+	/**
+	 * This Constructor is protected to avoid accidental misuse.
+	 * 
+	 * be sure to initialize the enumeration fully, by either adding it as a static
+	 * field in an extending class, or setting the ordinal by hand. You'll also have
+	 * to add the resulting object to a DynamicEnumeration for it to be completely
+	 * usable.
+	 * 
+	 * @param name
+	 */
+	protected EnumerationValue(String name) {
+		this(name, null);
+	}
+
+	/**
+	 * This Constructor is protected to avoid accidental misuse.
+	 * 
+	 * You'll have to add the resulting object to a Enumeration for it to be
+	 * completely usable.
+	 * 
+	 * @param name
+	 */
+	protected EnumerationValue(String name, Integer ordinal) {
+		this.name = Objects.requireNonNull(name, "Name of an EnumerationValue can never be null!");
+		this.ordinal = ordinal;
+		this.owner = null;
+	}
+
+	/**
+	 * @return the name of this enumeration value
+	 */
+	public String name() {
+		return name;
+	}
+
+	/**
+	 * @return the enumeration value represented by the given name
+	 */
+	public EnumerationValue valueOf(String name) {
+		return owner.valueOf(name);
+	}
+
+	/**
+	 * @return the ordinal value represented by this enumeration value
+	 */
+	public Integer ordinal() {
+		return ordinal;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return name();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Environment.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Environment.java
new file mode 100644
index 0000000..4b990e1
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Environment.java
@@ -0,0 +1,134 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the environment entity type. The {@link Environment} is a
+ * singleton within a connected data source.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Environment extends BaseEntity implements Datable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'MaxTestLevel' attribute name.
+	 */
+	public static final String ATTR_MAX_TEST_LEVEL = "Max_test_level";
+
+	/**
+	 * The 'BaseModelVersion' attribute name.
+	 */
+	public static final String ATTR_BASE_MODEL_VERSION = "Base_model_version";
+
+	/**
+	 * The 'AppModelVersion' attribute name.
+	 */
+	public static final String ATTR_APP_MODEL_VERSION = "AppModelVersion";
+
+	/**
+	 * The 'AppModelType' attribute name.
+	 */
+	public static final String ATTR_APP_MODEL_TYPE = "AppModelType";
+
+	/**
+	 * The 'Timezone' attribute name.
+	 */
+	public static final String ATTR_TIMEZONE = "Timezone";
+
+	/**
+	 * The 'MeaningOfAliases' attribute name.
+	 */
+	public static final String ATTR_MEANING_OF_ALIASES = "MeaningOfAliases";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Environment(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the max test level of this environment.
+	 *
+	 * @return The max test level is returned.
+	 */
+	public Integer getMaxTestLevel() {
+		return getValue(ATTR_MAX_TEST_LEVEL).extract();
+	}
+
+	/**
+	 * Returns the base model version of this environment.
+	 *
+	 * @return The base model version is returned.
+	 */
+	public String getBaseModelVersion() {
+		return getValue(ATTR_BASE_MODEL_VERSION).extract();
+	}
+
+	/**
+	 * Returns the application model version of this environment.
+	 *
+	 * @return The application model version is returned.
+	 */
+	public String getAppModelVersion() {
+		return getValue(ATTR_APP_MODEL_VERSION).extract();
+	}
+
+	/**
+	 * Returns the application model type of this environment.
+	 *
+	 * @return The application model type is returned.
+	 */
+	public String getAppModelType() {
+		return getValue(ATTR_APP_MODEL_TYPE).extract();
+	}
+
+	/**
+	 * Returns the time zone of this environment.
+	 *
+	 * @return The time zone is returned.
+	 */
+	public String getTimezone() {
+		return getValue(ATTR_TIMEZONE).extract();
+	}
+
+	/**
+	 * Returns the Meaning of aliases of this environment.
+	 *
+	 * @return The meaning of aliases are returned.
+	 */
+	public String[] getMeaningOfAliases() {
+		return getValue(ATTR_MEANING_OF_ALIASES).extract();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FileLink.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FileLink.java
new file mode 100644
index 0000000..f558b54
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FileLink.java
@@ -0,0 +1,506 @@
+/********************************************************************************
+ * Copyright (c) 2015-2020 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/**
+ * Utility class to manage links to externally stored files (local/remote).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class FileLink {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final State state;
+
+	private String remotePath;
+	private MimeType mimeType;
+	private String description;
+
+	private InputStream localStream;
+	private String localFileName;
+
+	private long size = -1;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param fileLink Will be copied.
+	 */
+	FileLink(FileLink fileLink) {
+		remotePath = fileLink.remotePath;
+		mimeType = fileLink.mimeType;
+		description = fileLink.description;
+		localStream = fileLink.localStream;
+		size = fileLink.size;
+		state = fileLink.state;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param remotePath The remote path.
+	 * @param mimeType   The MIME type of the linked file.
+	 */
+	private FileLink(String remotePath, MimeType mimeType) {
+		this.remotePath = remotePath;
+		this.mimeType = mimeType;
+
+		state = State.REMOTE;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param localPath The local {@link Path}.
+	 * @throws IOException Thrown in case of errors.
+	 */
+	private FileLink(InputStream localStream, String name, long size, MimeType mimeType, String description) throws IOException {
+		this.localStream = localStream;
+		this.mimeType = mimeType == null ? new MimeType("application/octet-stream") : mimeType;
+		this.size = size;
+		this.localFileName = name;
+		this.description = description;
+		state = State.LOCAL;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link FileLink} instance which remotely available.
+	 *
+	 * @param remotePath  The remote path.
+	 * @param mimeType    The MIME type.
+	 * @param description Description of the file.
+	 * @return The created {@code FileLink} instance is returned.
+	 */
+	public static FileLink newRemote(String remotePath, MimeType mimeType, String description) {
+		FileLink fileLink = new FileLink(remotePath, mimeType);
+		fileLink.setDescription(description);
+		return fileLink;
+	}
+
+	/**
+	 * Creates a new {@link FileLink} instance which locally available.
+	 *
+	 * @param localPath The local {@link Path} to the file.
+	 * @return The created {@code FileLink} instance is returned.
+	 * @throws IOException Thrown if unable to access file with given {@code
+	 * 		Path}       .
+	 */
+	public static FileLink newLocal(InputStream localStream, String name, long size, MimeType mimeType, String description) throws IOException {
+		return new FileLink(localStream, name, size, mimeType, description);
+	}
+	
+	public static FileLink newLocal(Path localPath) throws IOException {
+		if (Files.isDirectory(localPath)) {
+			throw new IllegalArgumentException("Local path is a directory.");
+		} else if (!Files.exists(localPath)) {
+			throw new IllegalArgumentException("Local path does not exist.");
+		} else if (!Files.isReadable(localPath)) {
+			throw new IllegalArgumentException("Local path is not readable.");
+		}
+		
+		InputStream localStream = Files.newInputStream(localPath);
+		long size = Files.size(localPath);
+		String name = localPath.getFileName().toString();
+		String mimeType = Files.probeContentType(localPath);
+		MimeType mimeT = mimeType == null ? null : new MimeType(mimeType);
+		return new FileLink(localStream, name, size, mimeT, name);
+	}
+
+	/**
+	 * Returns the name of the linked file.
+	 *
+	 * @return Name of the file is returned.
+	 * @throws IllegalStateException Thrown if unable to retrieve the file name.
+	 */
+	public String getFileName() {
+		Path fileNamePath = null;
+		String fileName = null;
+		if (isLocal()) {
+			fileName = this.localFileName;
+		} else if (isRemote()) {
+			try {
+				// on Windows, Paths.get() cannot handle file urls in the form
+				// file://REMOTE_HOST/path/filename
+				String fixedPath = remotePath.replaceFirst("file:", "");
+				fileNamePath = Paths.get(URLDecoder.decode(fixedPath, StandardCharsets.UTF_8.name())).getFileName();
+			} catch (UnsupportedEncodingException e) {
+				throw new IllegalStateException("Unable to decode remote path due to: " + e.getMessage(), e);
+			}
+			
+			if (fileNamePath == null) {
+				throw new IllegalStateException("File name is unknown.");
+			}
+			fileName = fileNamePath.toString();
+		}
+
+		return fileName;
+	}
+
+	/**
+	 * Returns the MIME type of the linked file.
+	 *
+	 * @return The MIME type is returned.
+	 */
+	public MimeType getMimeType() {
+		return mimeType;
+	}
+
+	/**
+	 * Checks whether a local {@link Path} is available for the linked file.
+	 *
+	 * @return Returns {@code true} if a local {@code Path} is available.
+	 */
+	public boolean isLocal() {
+		return localStream != null;
+	}
+
+	/**
+	 * Returns the local {@link InputStream} to the linked file. Calling this method is
+	 * only allowed if calling {@link #isLocal()} returns {@code
+	 * true}.
+	 *
+	 * @return The local {@code Path} to the linked file is returned.
+	 */
+	public InputStream getLocalStream() {
+		if (isLocal()) {
+			return localStream;
+		}
+
+		throw new IllegalStateException("Local path is not available.");
+	}
+
+	/**
+	 * This method is called by API providers to set the local {@link InputStream} once the
+	 * remote file was downloaded.
+	 *
+	 * @param localPath The local {@code InputStream} of the downloaded file.
+	 * @throws IllegalStateException Thrown if this file link is 'LOCAL'.
+	 */
+	public void setLocalStream(InputStream localStream) {
+		if (State.LOCAL == state) {
+			throw new IllegalStateException("It is not allowed to replace an existing local path.");
+		}
+
+		this.localStream = localStream;
+	}
+
+	/**
+	 * Checks whether a remote path is available for for linked file.
+	 *
+	 * @return Returns {@code true} if a remote path is available.
+	 */
+	public boolean isRemote() {
+		return remotePath != null && !remotePath.isEmpty();
+	}
+
+	/**
+	 * Returns the remote path to the linked file. Calling this method is only
+	 * allowed if calling {@link #isRemote()} returns {@code true}.
+	 *
+	 * @return The remote path to the linked file is returned.
+	 */
+	public String getRemotePath() {
+		if (isRemote()) {
+			return remotePath;
+		}
+
+		throw new IllegalStateException("Remote path is not available.");
+	}
+
+	/**
+	 * This method is called by API providers to set the remote path once the local
+	 * file has been uploaded.
+	 *
+	 * @param remotePath The remote path of the uploaded file.
+	 * @throws IllegalStateException Thrown if this file link is 'REMOTE'.
+	 */
+	public void setRemotePath(String remotePath) {
+		if (State.REMOTE == state) {
+			throw new IllegalStateException("It is not allowed to replace an existing remote path.");
+		}
+		this.remotePath = remotePath;
+	}
+
+	/**
+	 * Returns the description of the linked file.
+	 *
+	 * @return The description is returned.
+	 */
+	public String getDescription() {
+		return description == null ? "" : description;
+	}
+
+	/**
+	 * Sets a new description for the linked file.
+	 *
+	 * @param description The new description.
+	 */
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	/**
+	 * Returns the size of the linked file or {@code -1} if unknown.
+	 *
+	 * @return The file size in bytes is returned.
+	 */
+	public long getSize() {
+		return size;
+	}
+
+	/**
+	 * Returns the formatted file size of the linked file.
+	 *
+	 * @param format Used to format the size.
+	 * @return The formatted file size is returned.
+	 */
+	public String getSize(Format format) {
+		return format.getSize(size);
+	}
+
+	/**
+	 * This method is called by API providers to set the file size for the linked
+	 * file.
+	 *
+	 * @param size The size of the file in bytes.
+	 */
+	public void setFileSize(long size) {
+		this.size = size;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		if (State.LOCAL == state) {
+			if (!isLocal()) {
+				return "".hashCode();
+			}
+			return getLocalStream().hashCode();
+		}
+		if (!isRemote()) {
+			return "".hashCode();
+		}
+		return getRemotePath().hashCode();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (object instanceof FileLink) {
+			FileLink other = (FileLink) object;
+			if (state == other.state) {
+				if (State.LOCAL == state) {
+					if (!isLocal()) {
+						return !other.isLocal();
+					}
+					return getLocalStream().equals(other.getLocalStream());
+				}
+				if (!isRemote()) {
+					return !other.isRemote();
+				}
+				return getRemotePath().equals(other.getRemotePath());
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("FileLink(Description = ");
+
+		if (!getDescription().isEmpty()) {
+			sb.append(getDescription());
+		}
+
+		if (isLocal()) {
+			sb.append(", LocalPath = ").append(getLocalStream());
+		}
+
+		if (isRemote()) {
+			sb.append(", RemotePath = ").append(getRemotePath());
+		}
+
+		sb.append(", Size = ");
+		if (getSize() > 0) {
+			sb.append(getSize(Format.DECIMAL)).append(" / ").append(getSize(Format.BINARY));
+		} else {
+			sb.append("UNKNOWN");
+		}
+
+		return sb.append(')').toString();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Checks whether given {@link FileLink} may be treated as equal. This is the
+	 * case if either their local {@link Path}s or remote paths are equal.
+	 *
+	 * @param o1 The first {@code FileLink}.
+	 * @param o2 The second {@code FileLink}.
+	 * @return Returns {@code true} if either their local {@code Path}s or remote
+	 *         paths are equal.
+	 */
+	static boolean areEqual(FileLink o1, FileLink o2) {
+		return isLocalPathEqual(o1, o2) || isRemotePathEqual(o1, o2);
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Checks whether both {@link FileLink}s return {@code true} when
+	 * {@link #isLocal()} is called and their {@link Path}s are equal.
+	 *
+	 * @param o1 The first {@code FileLink}.
+	 * @param o2 The second {@code FileLink}.
+	 * @return Returns {@code true} if both {@code FileLink}s have a local
+	 *         {@code Path} which are equal.
+	 */
+	private static boolean isLocalPathEqual(FileLink o1, FileLink o2) {
+		return o1.isLocal() && o2.isLocal() && o1.getLocalStream().equals(o2.getLocalStream());
+	}
+
+	/**
+	 * Checks whether both {@link FileLink}s return {@code true} when
+	 * {@link #isRemote()} is called and their remote paths are equal.
+	 *
+	 * @param o1 The first {@code FileLink}.
+	 * @param o2 The second {@code FileLink}.
+	 * @return Returns {@code true} if both {@code FileLink}s have a remote path
+	 *         which are equal.
+	 */
+	private static boolean isRemotePathEqual(FileLink o1, FileLink o2) {
+		return o1.isRemote() && o2.isRemote() && o1.getRemotePath().equals(o2.getRemotePath());
+	}
+
+	// ======================================================================
+	// Inner classes
+	// ======================================================================
+
+	/**
+	 * Used to format a number of bytes into a human readable size.
+	 */
+	public enum Format {
+
+		// ======================================================================
+		// Enum constants
+		// ======================================================================
+
+		/**
+		 * Counts 1000 bits as 1 byte, so formats 110592 to '110.6 kB'.
+		 */
+		DECIMAL(1000, "kMGTPE"),
+
+		/**
+		 * Counts 1024 bits as 1 byte, so formats 110592 to '108.0 KiB'.
+		 */
+		BINARY(1024, "KMGTPE");
+
+		// ======================================================================
+		// Inner classes
+		// ======================================================================
+
+		private final String prefixChars;
+		private final int unit;
+
+		// ======================================================================
+		// Constructors
+		// ======================================================================
+
+		/**
+		 * Constructor.
+		 *
+		 * @param unit        The unit.
+		 * @param prefixChars The prefix characters.
+		 */
+		private Format(int unit, String prefixChars) {
+			this.prefixChars = prefixChars;
+			this.unit = unit;
+		}
+
+		// ======================================================================
+		// Private methods
+		// ======================================================================
+
+		/**
+		 * Formats given file size in bytes into a human readable one.
+		 *
+		 * @param size The number of bytes.
+		 * @return Formatted file size is returned.
+		 */
+		private String getSize(long size) {
+			if (size < 0) {
+				return "UNKNOWN";
+			} else if (size < unit) {
+				return size + " B";
+			}
+
+			int exponent = (int) (Math.log(size) / Math.log(unit));
+			String prefixChar = prefixChars.charAt(exponent - 1) + (DECIMAL == this ? "" : "i");
+			return String.format("%.1f %sB", size / Math.pow(unit, exponent), prefixChar);
+		}
+	}
+
+	/**
+	 * Used to preserve the initial state of a {@link FileLink}.
+	 */
+	private enum State {
+
+		/**
+		 * {@link FileLink} was initially only remotely available.
+		 */
+		REMOTE,
+
+		/**
+		 * {@link FileLink} was initially only locally available.
+		 */
+		LOCAL
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FilesAttachable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FilesAttachable.java
new file mode 100644
index 0000000..3ccb0a7
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FilesAttachable.java
@@ -0,0 +1,88 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'FileLinks' sequence field of an entity.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see FileLink
+ */
+public interface FilesAttachable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'FileLinks' attribute name.
+	 */
+	String ATTR_FILE_LINKS = "MDMLinks";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns current set of linked files of this entity.
+	 *
+	 * @return Current set of linked files are returned.
+	 */
+	default FileLink[] getFileLinks() {
+		return ((FileLink[]) getValue(ATTR_FILE_LINKS).extract()).clone();
+	}
+
+	/**
+	 * Replaces current set of linked files with given {@link FileLink}s.
+	 *
+	 * @param fileLinks The new {@code FileLink}s.
+	 */
+	default void setFileLinks(FileLink[] fileLinks) {
+		getValue(ATTR_FILE_LINKS).set(fileLinks);
+	}
+
+	/**
+	 * Adds given {@link FileLink} to the current set of linked files.
+	 *
+	 * @param fileLink The new {@code FileLink}.
+	 */
+	default void addFileLink(FileLink fileLink) {
+		FileLink[] fileLinks = getFileLinks();
+
+		FileLink[] newFileLinks = new FileLink[fileLinks.length + 1];
+		System.arraycopy(fileLinks, 0, newFileLinks, 0, fileLinks.length);
+		newFileLinks[fileLinks.length] = fileLink;
+		setFileLinks(newFileLinks);
+	}
+
+	/**
+	 * Removes given {@link FileLink} from current set of linked files.
+	 *
+	 * @param fileLink The {@code FileLink} which shall be removed.
+	 */
+	default void removeFileLink(FileLink fileLink) {
+		List<FileLink> fileLinks = new ArrayList<>(Arrays.asList(getFileLinks()));
+		fileLinks.remove(fileLink);
+		setFileLinks(fileLinks.toArray(new FileLink[fileLinks.size()]));
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FloatComplex.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FloatComplex.java
new file mode 100644
index 0000000..226f4a6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/FloatComplex.java
@@ -0,0 +1,100 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This class represents a complex value with real and imaginary parts of type
+ * {@code float}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class FloatComplex {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final float re;
+	private final float im;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param real      The real part.
+	 * @param imaginary The imaginary part.
+	 */
+	public FloatComplex(float real, float imaginary) {
+		re = real;
+		im = imaginary;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Parses given {@code String} where real and imaginary parts are separated by
+	 * one or more blanks. Furthermore both must be floating point numbers that can
+	 * be parsed by calling {@link Float#valueOf(String)}.
+	 *
+	 * @param s The {@code String} to be parsed.
+	 * @return The parsed {@link FloatComplex} value is returned.
+	 * @throws NumberFormatException Thrown if unable to parse the complex value.
+	 */
+	public static FloatComplex valueOf(String s) {
+		String[] values = s.split(" +");
+		if (values.length != 2) {
+			throw new NumberFormatException("Unable to parse complex value.");
+		}
+
+		return new FloatComplex(Float.parseFloat(values[0]), Float.parseFloat(values[1]));
+	}
+
+	/**
+	 * Returns the real part of this complex value.
+	 *
+	 * @return The real part is returned.
+	 */
+	public float real() {
+		return re;
+	}
+
+	/**
+	 * Returns the imaginary part of this complex value.
+	 *
+	 * @return The imaginary part is returned.
+	 */
+	public float imaginary() {
+		return im;
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this complex value.
+	 * The real and imaginary parts are separated with a blank.
+	 *
+	 * @return The {@code String} representation of this complex value.
+	 */
+	@Override
+	public String toString() {
+		return new StringBuilder().append(real()).append(' ').append(imaginary()).toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Interpolation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Interpolation.java
new file mode 100644
index 0000000..602d4e6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Interpolation.java
@@ -0,0 +1,75 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * This is the interpolation enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Interpolation extends EnumerationValue {
+
+	/**
+	 * No interpolation is used.
+	 */
+	public static final Interpolation NONE = new Interpolation("NONE", 0);
+
+	/**
+	 * Interpolation is linear.
+	 */
+	public static final Interpolation LINEAR = new Interpolation("LINEAR", 1);
+
+	/**
+	 * Interpolation is application specific.
+	 */
+	public static final Interpolation SPECIFIC = new Interpolation("SPECIFIC", 2);
+
+	private Interpolation(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	/**
+	 * Returns true if this interpolation is {@link #NONE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isNone() {
+		return NONE == this;
+	}
+
+	/**
+	 * Returns true if this interpolation is {@link #LINEAR}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLinear() {
+		return LINEAR == this;
+	}
+
+	/**
+	 * Returns true if this interpolation is {@link #SPECIFIC}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isSpecific() {
+		return SPECIFIC == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MeasuredValues.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MeasuredValues.java
new file mode 100644
index 0000000..1935ea0
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MeasuredValues.java
@@ -0,0 +1,278 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static java.util.stream.IntStream.range;
+import static org.eclipse.mdm.api.base.model.Value.readAt;
+
+import java.lang.reflect.Array;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.stream.Collectors;
+
+/**
+ * Class represents a sequence of measured values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class MeasuredValues {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final ScalarType scalarType;
+	private final Object values;
+	private final boolean[] flags;
+
+	/*
+	 * TODO: - replace name and unit with the corresponding Channel & Unit entities
+	 * - provide further information if required - provide an overall offset for
+	 * this value sequence
+	 */
+
+	private final String name;
+	private final String unit;
+
+	private final int length;
+
+	private final SequenceRepresentation sequenceRepresentation;
+	private final double[] generationParameters;
+	private final boolean independent;
+	private final AxisType axisType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param scalarType             The {@link ScalarType} of this measured values.
+	 * @param name                   This is the name of the corresponding
+	 *                               {@link Channel}.
+	 * @param unit                   Name of the unit the contained values are of.
+	 * @param sequenceRepresentation The {@link SequenceRepresentation} of the
+	 *                               measured values.
+	 * @param generationParameters   The generation parameters for the measured
+	 *                               values.
+	 * @param independent            The independent flag of the measured values.
+	 * @param axisType               The {@link AxisType} of the measured values.
+	 * @param values                 The measured values.
+	 * @param flags                  The validity flags of the measured values.
+	 * @throws IllegalArgumentException Thrown if values or flags is null or length
+	 *                                  of values and flags is not equal.
+	 */
+	MeasuredValues(ScalarType scalarType, String name, String unit, SequenceRepresentation sequenceRepresentation,
+			double[] generationParameters, boolean independent, AxisType axisType, Object values, boolean[] flags) {
+		this.name = name;
+		this.unit = (unit == null ? "" : unit);
+		this.scalarType = scalarType;
+		this.sequenceRepresentation = sequenceRepresentation;
+		this.generationParameters = generationParameters;
+		this.independent = independent;
+		this.axisType = axisType;
+		this.values = values;
+
+		if (values == null || flags == null) {
+			throw new IllegalArgumentException("Neither values nor flags is allowed to be null.");
+		} else if (Array.getLength(values) != flags.length) {
+			throw new IllegalArgumentException("Length of values and flags is not equal.");
+		}
+
+		this.flags = Arrays.copyOf(flags, flags.length);
+		length = flags.length;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of this measured values sequence.
+	 *
+	 * @return The name is returned.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the unit name for this measured values sequence.
+	 *
+	 * @return The unit name is returned.
+	 */
+	public String getUnit() {
+		return unit;
+	}
+
+	/**
+	 * Returns the {@link ScalarType} of this measured values sequence.
+	 *
+	 * @return The {@code ScalarType} is returned.
+	 */
+	public ScalarType getScalarType() {
+		return scalarType;
+	}
+
+	/**
+	 * Returns the number of values of this measured values sequence.
+	 *
+	 * @return The number of values is returned.
+	 */
+	public int getLength() {
+		return length;
+	}
+
+	/**
+	 * Returns the {@link SequenceRepresentation} of this measured values sequence.
+	 *
+	 * @return The {@code SequenceRepresentation} is returned.
+	 */
+	public SequenceRepresentation getSequenceRepresentation() {
+		return sequenceRepresentation;
+	}
+
+	/**
+	 * Returns the generation parameters for this measured values sequence.
+	 *
+	 * @return The generation parameters are returned.
+	 */
+	public double[] getGenerationParameters() {
+		return generationParameters;
+	}
+
+	/**
+	 * Returns the independent flag of this measured values sequence.
+	 *
+	 * @return The independent flag is returned.
+	 */
+	public boolean isIndependent() {
+		return independent;
+	}
+
+	/**
+	 * Returns the {@link AxisType} of this measured values sequence.
+	 *
+	 * @return The {@code AxisType} is returned.
+	 */
+	public AxisType getAxisType() {
+		return axisType;
+	}
+
+	/**
+	 * Returns a typed {@link ValueIterator}. Its usage is described below:
+	 *
+	 * <pre>
+	 * // assume the measuredValues().getScalarType() == ScalarType.BYTE
+	 * ValueIterator&lt;Byte&gt; valueIterator = measuredValues().iterator();
+	 * while (valueIterator.hasNext()) {
+	 * 	boolean isCurrentValid = valueIterator.isValid();
+	 * 	Byte currentValue = valueIterator.next();
+	 * }
+	 * </pre>
+	 *
+	 * @param <E> This type has to be derived from the {@link ScalarType} of this
+	 *            measured values.
+	 * @return A typed {@code ValueIterator} is returned.
+	 */
+	public <E> ValueIterator<E> iterator() {
+		// TODO provide custom implementations for each type and typed
+		// nextType() methods
+		// idea: getScalarType().createIterator(values, flags); // <- package
+		// private
+		return new ValueIterator<E>() {
+			private int index = 0;
+
+			@Override
+			public boolean hasNext() {
+				return index < length;
+			}
+
+			@Override
+			public boolean isValid() {
+				return flags[index];
+			}
+
+			@Override
+			@SuppressWarnings("unchecked")
+			public E next() {
+				if (hasNext()) {
+					return (E) Array.get(values, index++);
+				}
+				throw new NoSuchElementException("Subsequent value is not available.");
+			}
+		};
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this measured
+	 * values. If this sequence contains more than 10 values, only the first and
+	 * last 5 values are written. If a value is marked as not valid, then 'XX' is
+	 * written instead of its value.
+	 *
+	 * @return The {@code String} representation of this entity.
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("MeasuredValues(ChannelName = ").append(getName());
+		sb.append(", ScalarType = ").append(getScalarType());
+
+		if (!getUnit().isEmpty()) {
+			sb.append(", Unit = ").append(getUnit());
+		}
+
+		sb.append(", Values = [");
+		String notValidMarker = "XX";
+		if (getLength() > 10) {
+			sb.append(range(0, 5).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
+					.collect(Collectors.joining(", ")));
+			sb.append(", ..., ");
+			sb.append(range(length - 5, length).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
+					.collect(Collectors.joining(", ")));
+		} else if (getLength() > 0) {
+			sb.append(range(0, length).mapToObj(i -> flags[i] ? readAt(values, i) : notValidMarker)
+					.collect(Collectors.joining(", ")));
+		}
+
+		return sb.append("])").toString();
+	}
+
+	// ======================================================================
+	// Inner Types
+	// ======================================================================
+
+	/**
+	 * The measured values iterator.
+	 *
+	 * @param <E> Type of the returned values.
+	 * @since 1.0.0
+	 * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+	 */
+	public interface ValueIterator<E> extends Iterator<E> {
+
+		/**
+		 * Returns true if the current value is marked as valid.
+		 *
+		 * @return True if current value is valid.
+		 */
+		boolean isValid();
+
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Measurement.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Measurement.java
new file mode 100644
index 0000000..d7ee766
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Measurement.java
@@ -0,0 +1,170 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Implementation of the measurement entity type. The measurement entity holds
+ * data of a measurement or an analysis. It is the linking point to the
+ * following related data:
+ *
+ * <ul>
+ * <li>To ensure any persisted measurement can always be reinterpreted it,
+ * always should have relations to {@link ContextRoot}s that contain the
+ * description of the test run. All measurement entities under the same parent
+ * {@link TestStep} must reference the same {@code
+ * 		ContextRoot}.</li>
+ * <li>The results of a test run are accessible via the children of type
+ * {@link ChannelGroup} and {@link Channel}.</li>
+ * </ul>
+ *
+ * The name of a measurement should be chosen in a speaking way. It has to be
+ * unique under the parent {@code TestStep}.
+ * <p>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ParameterSet
+ */
+public class Measurement extends BaseEntity
+		implements ContextDescribable, Datable, Deletable, Describable, FilesAttachable, Tagable, StatusAttachable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link TestStep} parent type.
+	 */
+	public static final Class<TestStep> PARENT_TYPE_TESTSTEP = TestStep.class;
+
+	/**
+	 * The {@link ChannelGroup} child type.
+	 */
+	public static final Class<ChannelGroup> CHILD_TYPE_CHANNELGROUP = ChannelGroup.class;
+
+	/**
+	 * The {@link ParameterSet} child type.
+	 */
+	public static final Class<ParameterSet> CHILD_TYPE_PARAMETERSET = ParameterSet.class;
+
+	/**
+	 * The {@link Channel} child type.
+	 */
+	public static final Class<Channel> CHILD_TYPE_CHANNEL = Channel.class;
+
+	/**
+	 * The 'MeasurementBegin' attribute name.
+	 */
+	public static final String ATTR_MEASUREMENT_BEGIN = "MeasurementBegin";
+
+	/**
+	 * The 'MeasurementEnd' attribute name.
+	 */
+	public static final String ATTR_MEASUREMENT_END = "MeasurementEnd";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Measurement(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the time stamp of the date when this measurement was started.
+	 *
+	 * @return Measurement execution start time stamp is returned.
+	 */
+	public LocalDateTime getMeasurementBegin() {
+		return getValue(ATTR_MEASUREMENT_BEGIN).extract();
+	}
+
+	/**
+	 * Sets new time stamp for the date when this measurement was started.
+	 *
+	 * @param measurementBegin The new measurement start time stamp.
+	 */
+	public void setMeasurementBegin(LocalDateTime measurementBegin) {
+		getValue(ATTR_MEASUREMENT_BEGIN).set(measurementBegin);
+	}
+
+	/**
+	 * Returns the time stamp of the date when this measurement was finished.
+	 *
+	 * @return Measurement execution end time stamp is returned.
+	 */
+	public LocalDateTime getMeasurementEnd() {
+		return getValue(ATTR_MEASUREMENT_END).extract();
+	}
+
+	/**
+	 * Sets new time stamp for the date when this measurement was finished.
+	 *
+	 * @param measurementEnd The new measurement execution end time stamp.
+	 */
+	public void setMeasurementEnd(LocalDateTime measurementEnd) {
+		getValue(ATTR_MEASUREMENT_END).set(measurementEnd);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<ContextType> loadContextTypes(BaseEntityManager manager) throws DataAccessException {
+		return manager.loadContextTypes(this);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<ContextType, ContextRoot> loadContexts(BaseEntityManager manager, ContextType... contextTypes)
+			throws DataAccessException {
+
+		Map<ContextType, ContextRoot> map = new HashMap<>();
+
+		for (ContextType contextType : contextTypes) {
+			ContextRoot c = getCore().getMutableStore().get(ContextRoot.class, contextType);
+			if (c != null) {
+				map.put(contextType, c);
+			}
+		}
+		if (map.isEmpty()) {
+			return manager.loadContexts(this, contextTypes);
+		} else {
+			return map;
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MimeType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MimeType.java
new file mode 100644
index 0000000..8abbc4c
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/MimeType.java
@@ -0,0 +1,136 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Locale;
+
+/**
+ * Class provides easy to use MIME type comparison methods.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Entity
+ */
+public final class MimeType {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final String internal;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param mimeType The MIME type will be changed to lower case.
+	 */
+	public MimeType(String mimeType) {
+		internal = mimeType.toLowerCase(Locale.ROOT);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	public MimeType addSubType(String name) {
+		return new MimeType(internal + '.' + name);
+	}
+
+	/**
+	 * Checks whether given {@code MimeType} is either the same as or a sub type of
+	 * this MIME type. See the following examples:
+	 *
+	 * <pre>
+	 * MimeType type = new MimeType("application/x-asam.aomeasurement");
+	 * MimeType subType = new MimeType("application/x-asam.aomeasurement.subtype");
+	 *
+	 * type.isParentOf(subType); // true
+	 * subType.isParentOf(type); // false
+	 * type.isParentOf(type); // true
+	 * </pre>
+	 *
+	 * @param mimeType The checked type.
+	 * @return Returns true if either this MIME type and given one are the same or
+	 *         the given one is a sub type of this MIME type.
+	 */
+	public boolean isParentOf(MimeType mimeType) {
+		return mimeType != null && mimeType.compareString().startsWith(compareString());
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public int hashCode() {
+		return internal.hashCode();
+	}
+
+	/**
+	 * Checks whether given {@code Object} represents the same type as this MIME
+	 * type.
+	 *
+	 * <pre>
+	 * MimeType type = new MimeType("application/x-asam.aomeasurement");
+	 * MimeType equalType = new MimeType("application/x-asam.aomeasurement");
+	 * MimeType subType = new MimeType("application/x-asam.aomeasurement.subtype");
+	 * MimeType anotherType = new MimeType("application/x-asam.aounit");
+	 *
+	 * type.equals(equalType); // true
+	 * subType.equals(type); // false
+	 * type.equals(anotherType); // false
+	 * </pre>
+	 *
+	 * @param object The checked object.
+	 * @return True if given object is of type {@code MimeType} and represents
+	 *         exactly the same type as this MIME type.
+	 */
+	@Override
+	public boolean equals(Object object) {
+		if (object instanceof MimeType) {
+			return internal.equals(((MimeType) object).internal);
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns the MIME type.
+	 *
+	 * @return The MIME type is returned in lower case.
+	 */
+	@Override
+	public String toString() {
+		return internal;
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Adds a termination character to the internally stored string representation.
+	 *
+	 * @return A closed comparison string is returned.
+	 */
+	private String compareString() {
+		return internal + '.';
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Parameter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Parameter.java
new file mode 100644
index 0000000..2d38d22
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Parameter.java
@@ -0,0 +1,90 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.time.LocalDateTime;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the parameter entity type. Instances of this class hold a
+ * value in its {@code String} representation, which is converted upon request
+ * and provided as a virtual {@link Value}. The returned {@code Value} is for
+ * displaying purposes only. To change the value, held by this parameter, one of
+ * its {@code setXYValue(XY)} methods has to be used. {@link ValueType}s
+ * supported by this parameter are listed below:
+ *
+ * <ul>
+ * <li>{@link ValueType#STRING}</li>
+ * <li>{@link ValueType#DATE}</li>
+ * <li>{@link ValueType#BOOLEAN}</li>
+ * <li>{@link ValueType#BYTE}</li>
+ * <li>{@link ValueType#SHORT}</li>
+ * <li>{@link ValueType#INTEGER}</li>
+ * <li>{@link ValueType#LONG}</li>
+ * <li>{@link ValueType#FLOAT}</li>
+ * <li>{@link ValueType#DOUBLE}</li>
+ * <li>{@link ValueType#FLOAT_COMPLEX}</li>
+ * <li>{@link ValueType#DOUBLE_COMPLEX}</li>
+ * </ul>
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see ParameterSet
+ * @see #getVirtualValue()
+ * @see #setObjectValue(Object, Unit)
+ * @see #setStringValue(String)
+ * @see #setDateValue(LocalDateTime)
+ * @see #setBooleanValue(Boolean)
+ * @see #setByteValue(Byte, Unit)
+ * @see #setShortValue(Short, Unit)
+ * @see #setIntegerValue(Integer, Unit)
+ * @see #setLongValue(Long, Unit)
+ * @see #setFloatValue(Float, Unit)
+ * @see #setDoubleValue(Double, Unit)
+ * @see #setFloatComplexValue(FloatComplex, Unit)
+ * @see #setDoubleComplexValue(DoubleComplex, Unit)
+ */
+public final class Parameter extends BaseParameter {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'ScalarType' attribute name.
+	 */
+	public static final String ATTR_SCALAR_TYPE = "DataType";
+
+	/**
+	 * The 'Value' attribute name.
+	 */
+	public static final String ATTR_VALUE = "Value";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Parameter(Core core) {
+		super(ATTR_SCALAR_TYPE, ATTR_VALUE, core);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ParameterSet.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ParameterSet.java
new file mode 100644
index 0000000..a774cd1
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ParameterSet.java
@@ -0,0 +1,136 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the parameter set entity type. Instances of this class
+ * group a set of further describing data stored in {@link Parameter}s.
+ * Parameter sets are attached either to a {@link Measurement} or
+ * {@link Channel}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ParameterSet extends BaseEntity implements Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Measurement} parent type.
+	 */
+	public static final Class<Measurement> PARENT_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The {@link ChannelGroup} parent type.
+	 */
+	public static final Class<Channel> PARENT_TYPE_CHANNEL = Channel.class;
+
+	/**
+	 * The 'Version' attribute name.
+	 */
+	public static final String ATTR_VERSION = "Version";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	ParameterSet(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link Parameter} identified by given name.
+	 *
+	 * @param name The name of the {@code Parameter}.
+	 * @return The {@code Optional} is empty if a {@code Parameter} with given name
+	 *         does not exist.
+	 */
+	public Optional<Parameter> getParameter(String name) {
+		return getParameters().stream().filter(p -> p.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all available {@link Parameter}s related to this parameter set.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<Parameter> getParameters() {
+		return getCore().getChildrenStore().get(Parameter.class);
+	}
+
+	/**
+	 * Removes the {@link Parameter} identified by given name.
+	 *
+	 * @param name Name of the {@code Parameter} that have to be removed.
+	 * @return Returns {@code true} if the {@code Parameter} with given name has
+	 *         been removed.
+	 */
+	public boolean removeParameter(String name) {
+		Optional<Parameter> parameter = getParameter(name);
+		if (parameter.isPresent()) {
+			getCore().getChildrenStore().remove(parameter.get());
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Returns the version of this parameter set.
+	 *
+	 * @return The version is returned.
+	 */
+	public String getVersion() {
+		return getValue(ATTR_VERSION).extract();
+	}
+
+	/**
+	 * Sets new version for this parameter set.
+	 *
+	 * @param version The new version.
+	 */
+	public void setVersion(String version) {
+		getValue(ATTR_VERSION).set(version);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append('(');
+		sb.append(getValues().values().stream().map(Value::toString).collect(Collectors.joining(", ")));
+		return sb.append(", Parameters = ").append(getParameters()).append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/PhysicalDimension.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/PhysicalDimension.java
new file mode 100644
index 0000000..aa67bcc
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/PhysicalDimension.java
@@ -0,0 +1,238 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the physical dimension entity type. Each {@link Unit} must
+ * have a relation to an instance of this type. The attributes represent the
+ * exponents of the seven SI base units and additionally the angle exponent as
+ * defined in the ASAM NVH model. A {@code Unit} with a certain physical
+ * dimension can be converted to all units having the same relation. Names of
+ * the physical dimensions have to be unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class PhysicalDimension extends BaseEntity implements Describable, Deletable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Length' attribute name.
+	 */
+	public static final String ATTR_LENGTH = "Length";
+
+	/**
+	 * The 'Mass' attribute name.
+	 */
+	public static final String ATTR_MASS = "Mass";
+
+	/**
+	 * The 'Time' attribute name.
+	 */
+	public static final String ATTR_TIME = "Time";
+
+	/**
+	 * The 'Current' attribute name.
+	 */
+	public static final String ATTR_CURRENT = "Current";
+
+	/**
+	 * The 'Temperature' attribute name.
+	 */
+	public static final String ATTR_TEMPERATURE = "Temperature";
+
+	/**
+	 * The 'MolarAmount' attribute name.
+	 */
+	public static final String ATTR_MOLAR_AMOUNT = "MolarAmount";
+
+	/**
+	 * The 'LuminousIntensity' attribute name.
+	 */
+	public static final String ATTR_LUMINOUS_INTENSITY = "LuminousIntensity";
+
+	/**
+	 * The 'Angle' attribute name.
+	 */
+	public static final String ATTR_ANGLE = "angle";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	PhysicalDimension(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the length exponent of this physical dimension.
+	 *
+	 * @return The length exponent is returned.
+	 */
+	public Integer getLength() {
+		return getValue(ATTR_LENGTH).extract();
+	}
+
+	/**
+	 * Sets new length exponent for this physical dimension.
+	 *
+	 * @param exponent The new length exponent.
+	 */
+	public void setLength(Integer exponent) {
+		getValue(ATTR_LENGTH).set(exponent);
+	}
+
+	/**
+	 * Returns the mass exponent of this physical dimension.
+	 *
+	 * @return The mass exponent is returned.
+	 */
+	public Integer getMass() {
+		return getValue(ATTR_MASS).extract();
+	}
+
+	/**
+	 * Sets new mass exponent for this physical dimension.
+	 *
+	 * @param exponent The new mass exponent.
+	 */
+	public void setMass(Integer exponent) {
+		getValue(ATTR_MASS).set(exponent);
+	}
+
+	/**
+	 * Returns the time exponent of this physical dimension.
+	 *
+	 * @return The time exponent is returned.
+	 */
+	public Integer getTime() {
+		return getValue(ATTR_TIME).extract();
+	}
+
+	/**
+	 * Sets new time exponent for this physical dimension.
+	 *
+	 * @param exponent The new time exponent.
+	 */
+	public void setTime(Integer exponent) {
+		getValue(ATTR_TIME).set(exponent);
+	}
+
+	/**
+	 * Returns the current exponent of this physical dimension.
+	 *
+	 * @return The current exponent is returned.
+	 */
+	public Integer getCurrent() {
+		return getValue(ATTR_CURRENT).extract();
+	}
+
+	/**
+	 * Sets new current exponent for this physical dimension.
+	 *
+	 * @param exponent The new current exponent.
+	 */
+	public void setCurrent(Integer exponent) {
+		getValue(ATTR_CURRENT).set(exponent);
+	}
+
+	/**
+	 * Returns the temperature exponent of this physical dimension.
+	 *
+	 * @return The temperature exponent is returned.
+	 */
+	public Integer getTemperature() {
+		return getValue(ATTR_TEMPERATURE).extract();
+	}
+
+	/**
+	 * Sets new temperature exponent for this physical dimension.
+	 *
+	 * @param exponent The new temperature exponent.
+	 */
+	public void setTemperature(Integer exponent) {
+		getValue(ATTR_TEMPERATURE).set(exponent);
+	}
+
+	/**
+	 * Returns the molar amount exponent of this physical dimension.
+	 *
+	 * @return The molar amount exponent is returned.
+	 */
+	public Integer getMolarAmount() {
+		return getValue(ATTR_MOLAR_AMOUNT).extract();
+	}
+
+	/**
+	 * Sets new molar amount exponent for this physical dimension.
+	 *
+	 * @param exponent The new molar amount exponent.
+	 */
+	public void setMolarAmount(Integer exponent) {
+		getValue(ATTR_MOLAR_AMOUNT).set(exponent);
+	}
+
+	/**
+	 * Returns the luminous intensity exponent of this physical dimension.
+	 *
+	 * @return The luminous intensity exponent is returned.
+	 */
+	public Integer getLuminousIntensity() {
+		return getValue(ATTR_LUMINOUS_INTENSITY).extract();
+	}
+
+	/**
+	 * Sets new luminous intensity exponent for this physical dimension.
+	 *
+	 * @param exponent The new luminous intensity exponent.
+	 */
+	public void setLuminousIntensity(Integer exponent) {
+		getValue(ATTR_LUMINOUS_INTENSITY).set(exponent);
+	}
+
+	/**
+	 * Returns the angle exponent of this physical dimension.
+	 *
+	 * @return The angle exponent is returned.
+	 */
+	public Integer getAngle() {
+		return getValue(ATTR_ANGLE).extract();
+	}
+
+	/**
+	 * Sets new angle exponent for this physical dimension.
+	 *
+	 * @param exponent The new angle exponent.
+	 */
+	public void setAngle(Integer exponent) {
+		getValue(ATTR_ANGLE).set(exponent);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Quantity.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Quantity.java
new file mode 100644
index 0000000..a0e9cb8
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Quantity.java
@@ -0,0 +1,191 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the quantity entity type. {@link Channel}s are based on
+ * entities of this type. Each quantity has a relation to a default
+ * {@link Unit}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Quantity extends BaseEntity implements Datable, Deletable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'DefaultRank' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_RANK = "DefaultRank";
+
+	/**
+	 * The 'DefaultDimension' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_DIMENSION = "DefDimension";
+
+	/**
+	 * The 'DefaultTypeSize' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_TYPE_SIZE = "DefTypeSize";
+
+	/**
+	 * The 'DefaultChannelName' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_CHANNEL_NAME = "DefMQName";
+
+	/**
+	 * The 'DefaultScalarType' attribute name.
+	 */
+	public static final String ATTR_DEFAULT_SCALAR_TYPE = "DefDataType";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Quantity(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the default rank of this quantity.
+	 *
+	 * @return The default rank is returned.
+	 */
+	public Integer getDefaultRank() {
+		return getValue(ATTR_DEFAULT_RANK).extract();
+	}
+
+	/**
+	 * Sets new default rank for this quantity.
+	 *
+	 * @param defaultRank The new default rank.
+	 */
+	public void setDefaultRank(Integer defaultRank) {
+		getValue(ATTR_DEFAULT_RANK).set(defaultRank);
+	}
+
+	/**
+	 * Returns the default dimension of this quantity.
+	 *
+	 * @return The default dimension is returned.
+	 */
+	public int[] getDefaultDimension() {
+		return getValue(ATTR_DEFAULT_DIMENSION).extract();
+	}
+
+	/**
+	 * Sets new default dimension for this quantity.
+	 *
+	 * @param defaultDimension The new default dimension.
+	 */
+	public void setDefaultDimension(int[] defaultDimension) {
+		getValue(ATTR_DEFAULT_DIMENSION).set(defaultDimension);
+	}
+
+	/**
+	 * Returns the default type size of this quantity.
+	 *
+	 * @return The default type size is returned.
+	 */
+	public Integer getDefaultTypeSize() {
+		return getValue(ATTR_DEFAULT_TYPE_SIZE).extract();
+	}
+
+	/**
+	 * Sets new default type size for this quantity.
+	 *
+	 * @param defaultTypeSize The new default type size.
+	 */
+	public void setDefaultTypeSize(Integer defaultTypeSize) {
+		getValue(ATTR_DEFAULT_TYPE_SIZE).set(defaultTypeSize);
+	}
+
+	/**
+	 * Returns the default {@link Channel} name of this quantity.
+	 *
+	 * @return The default {@code Channel} name is returned.
+	 */
+	public String getDefaultChannelName() {
+		return getValue(ATTR_DEFAULT_CHANNEL_NAME).extract();
+	}
+
+	/**
+	 * Sets new default {@link Channel} name for this quantity.
+	 *
+	 * @param defaultChannelName The new default {@code Channel} name.
+	 */
+	public void setDefaultChannelName(String defaultChannelName) {
+		getValue(ATTR_DEFAULT_CHANNEL_NAME).set(defaultChannelName);
+	}
+
+	/**
+	 * Returns the default {@link ScalarType} of this quantity.
+	 *
+	 * @return The default {@code ScalarType} is returned.
+	 */
+	public ScalarType getDefaultScalarType() {
+		return getValue(ATTR_DEFAULT_SCALAR_TYPE).extract();
+	}
+
+	/**
+	 * Sets new default {@link ScalarType} for this quantity.
+	 *
+	 * @param defaultScalarType The new default {@code ScalarType}.
+	 * @throws IllegalArgumentException Thrown if given {@code ScalarType} is
+	 *                                  {@link ScalarType#UNKNOWN}.
+	 */
+	public void setDefaultScalarType(ScalarType defaultScalarType) {
+		if (defaultScalarType.isUnknown()) {
+			throw new IllegalArgumentException(
+					"Default scalar type constant is not allowed to be '" + defaultScalarType + "'.");
+		}
+
+		getValue(ATTR_DEFAULT_SCALAR_TYPE).set(defaultScalarType);
+	}
+
+	/**
+	 * Returns the default {@link Unit} of this quantity.
+	 *
+	 * @return The default {@code Unit} is returned.
+	 */
+	public Unit getDefaultUnit() {
+		return getCore().getMutableStore().get(Unit.class);
+	}
+
+	/**
+	 * Sets new default {@link Unit} for this quantity.
+	 *
+	 * @param defaultUnit The new default {@code Unit}.
+	 */
+	public void setDefaultUnit(Unit defaultUnit) {
+		getCore().getMutableStore().set(defaultUnit);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ScalarType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ScalarType.java
new file mode 100644
index 0000000..cf8ece3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ScalarType.java
@@ -0,0 +1,434 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Array;
+import java.time.LocalDateTime;
+
+/**
+ * Scalar type enumeration is a {@link MeasuredValues} factory. Another context
+ * where this enumeration is used is the storage of values, represented by the
+ * constants of this enumeration, in their {@code String} representation (see:
+ * {@link BaseParameter}).
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+
+public final class ScalarType extends EnumerationValue {
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code String} values.
+	 */
+	public static final ScalarType STRING = new ScalarType(0, "STRING", ValueType.STRING_SEQUENCE, String.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code LocalDateTime} values.
+	 */
+	public static final ScalarType DATE = new ScalarType(1, "DATE", ValueType.DATE_SEQUENCE, LocalDateTime.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code boolean} values.
+	 */
+	public static final ScalarType BOOLEAN = new ScalarType(2, "BOOLEAN", ValueType.BOOLEAN_SEQUENCE, boolean.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code byte} values.
+	 */
+	public static final ScalarType BYTE = new ScalarType(3, "BYTE", ValueType.BYTE_SEQUENCE, byte.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code short} values.
+	 */
+	public static final ScalarType SHORT = new ScalarType(4, "SHORT", ValueType.SHORT_SEQUENCE, short.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code int} values.
+	 */
+	public static final ScalarType INTEGER = new ScalarType(5, "INTEGER", ValueType.INTEGER_SEQUENCE, int.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code long} values.
+	 */
+	public static final ScalarType LONG = new ScalarType(6, "LONG", ValueType.LONG_SEQUENCE, long.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code float} values.
+	 */
+	public static final ScalarType FLOAT = new ScalarType(7, "FLOAT", ValueType.FLOAT_SEQUENCE, float.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code double} values.
+	 */
+	public static final ScalarType DOUBLE = new ScalarType(8, "DOUBLE", ValueType.DOUBLE_SEQUENCE, double.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code byte[]} values.
+	 */
+	public static final ScalarType BYTE_STREAM = new ScalarType(9, "BYTE_STREAM", ValueType.BYTE_STREAM_SEQUENCE,
+			byte[].class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code FloatComplex} values.
+	 */
+	public static final ScalarType FLOAT_COMPLEX = new ScalarType(10, "FLOAT_COMPLEX", ValueType.FLOAT_COMPLEX_SEQUENCE,
+			FloatComplex.class);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code DoubleComplex} values.
+	 */
+	public static final ScalarType DOUBLE_COMPLEX = new ScalarType(11, "DOUBLE_COMPLEX",
+			ValueType.DOUBLE_COMPLEX_SEQUENCE, DoubleComplex.class);
+
+	/**
+	 * {@link MeasuredValues} are not allowed to be of this type. This constant may
+	 * be used in other contexts.
+	 */
+	public static final ScalarType ENUMERATION = new ScalarType(12, "ENUMERATION", ValueType.ENUMERATION_SEQUENCE);
+
+	/**
+	 * A {@link MeasuredValues} with this type contains an array sequence of
+	 * {@code FileLink} values.
+	 */
+	public static final ScalarType FILE_LINK = new ScalarType(13, "FILE_LINK", ValueType.FILE_LINK_SEQUENCE,
+			FileLink.class);
+
+	/**
+	 * TODO ...
+	 */
+	public static final ScalarType BLOB = new ScalarType(14, "BLOB", ValueType.BLOB, Object.class);
+
+	/**
+	 * {@link MeasuredValues} are not allowed to be of this type. This constant may
+	 * be used in other contexts.
+	 */
+	public static final ScalarType UNKNOWN = new ScalarType(15, "UNKNOWN", ValueType.UNKNOWN);
+
+	private final ValueType valueType;
+	private final Class<?> arrayType;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param ord       ordinal number of the enum value
+	 * @param name      name of the enum value
+	 * @param valueType The associated {@link ValueType}.
+	 */
+	private ScalarType(int ord, String name, ValueType valueType) {
+		super(name, ord);
+		this.valueType = valueType;
+		arrayType = null;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param ord           ordinal number of the enum value
+	 * @param name          name of the enum value
+	 * @param valueType     The associated {@link ValueType}.
+	 * @param componentType The component type of the array held by instances of
+	 *                      {@link MeasuredValues}.
+	 */
+	private ScalarType(int ord, String name, ValueType valueType, Class<?> componentType) {
+		super(name, ord);
+		this.valueType = valueType;
+		arrayType = Array.newInstance(componentType, 0).getClass();
+	}
+
+	/**
+	 * Creates a new {@link MeasuredValues} initialized with given name, unit and
+	 * values including the related validity flags.
+	 *
+	 * @param name                   This is the name of the corresponding
+	 *                               {@link Channel}.
+	 * @param unit                   Name of the unit the contained values are of.
+	 * @param sequenceRepresentation The {@link SequenceRepresentation} of the
+	 *                               measured values.
+	 * @param independent            The independent flag of the measured values.
+	 * @param axisType               The {@link AxisType} of the measured values.
+	 * @param input                  The measured values.
+	 * @param flags                  The validity flags of the measured values.
+	 * @return The created {@code MeasuredValues} is returned.
+	 * @throws IllegalStateException    Thrown if {@link #isEnumeration()} or
+	 *                                  {@link #isUnknown()} returns {@code true}.
+	 * @throws IllegalArgumentException Thrown if given values are not assignment
+	 *                                  compatible.
+	 */
+	public MeasuredValues createMeasuredValues(String name, String unit, SequenceRepresentation sequenceRepresentation,
+			double[] generationParameters, boolean independent, AxisType axisType, Object input, boolean[] flags) {
+		if (isEnumeration() || isUnknown()) {
+			throw new IllegalStateException("It is not allowed to create measured values of type '" + this + "'.");
+		} else if (!arrayType.isInstance(input)) {
+			throw new IllegalArgumentException("Given values of type '" + input.getClass() + "'.");
+		}
+
+		return new MeasuredValues(this, name, unit, sequenceRepresentation, generationParameters, independent, axisType,
+				input, flags);
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #STRING}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isString() {
+		return STRING == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #DATE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDate() {
+		return DATE == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BOOLEAN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBoolean() {
+		return BOOLEAN == this;
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isNumericalType() {
+		return isIntegerType() || isFloatType();
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #LONG}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isIntegerType() {
+		return isByte() || isShort() || isInteger() || isLong();
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BYTE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByte() {
+		return BYTE == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #SHORT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isShort() {
+		return SHORT == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #INTEGER}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isInteger() {
+		return INTEGER == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #LONG}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLong() {
+		return LONG == this;
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFloatType() {
+		return isFloat() || isDouble();
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #FLOAT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloat() {
+		return FLOAT == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #DOUBLE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDouble() {
+		return DOUBLE == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BYTE_STREAM}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteStream() {
+		return BYTE_STREAM == this;
+	}
+
+	/**
+	 * Returns true if this scalar type on of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT_COMPLEX}</li>
+	 * <li>{@link #DOUBLE_COMPLEX}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isComplexType() {
+		return isFloatComplex() || isDoubleComplex();
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #FLOAT_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatComplex() {
+		return FLOAT_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #DOUBLE_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleComplex() {
+		return DOUBLE_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #ENUMERATION}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEnumeration() {
+		return ENUMERATION == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #FILE_LINK}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFileLink() {
+		return FILE_LINK == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #BLOB}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBlob() {
+		return BLOB == this;
+	}
+
+	/**
+	 * Returns true if this scalar type is {@link #UNKNOWN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isUnknown() {
+		return UNKNOWN == this;
+	}
+
+	/**
+	 * Returns the associated {@link ValueType}.
+	 *
+	 * @return The associated {@code ValueType} is returned.
+	 */
+	public ValueType toValueType() {
+		return valueType;
+	}
+
+	/**
+	 * Returns the non sequence {@link ValueType} of the associated {@code
+	 * ValueType}.
+	 *
+	 * @return The non sequence {@code ValueType} is returned.
+	 */
+	public ValueType toSingleValueType() {
+		return valueType.toSingleType();
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/SequenceRepresentation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/SequenceRepresentation.java
new file mode 100644
index 0000000..51ab0d1
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/SequenceRepresentation.java
@@ -0,0 +1,262 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * The sequence representation to describe the storage type of measured values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Channel
+ */
+public class SequenceRepresentation extends EnumerationValue {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Measured values are stored as is and values are therefore immediately
+	 * available.
+	 */
+	public static final SequenceRepresentation EXPLICIT = new SequenceRepresentation("EXPLICIT", 0);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> = p for i
+	 * &isin; [1, n], n is the total number of values and generation parameter p
+	 * (offset).
+	 */
+	public static final SequenceRepresentation IMPLICIT_CONSTANT = new SequenceRepresentation("IMPLICIT_CONSTANT", 1);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+(i-1)*p<sub>2</sub> for i &isin; [1, n], n is the total number
+	 * of values and generation parameters p<sub>1</sub> (start value) and
+	 * p<sub>2</sub> (increment).
+	 */
+	public static final SequenceRepresentation IMPLICIT_LINEAR = new SequenceRepresentation("IMPLICIT_LINEAR", 2);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+((i-1)mod(p<sub>3</sub>-p<sub>1</sub>)/p<sub>2</sub>)*
+	 * p<sub>2</sub> for i &isin; [1, n], n is the total number of values and
+	 * generation parameters p<sub>1</sub> (start value), p<sub>2</sub> (increment)
+	 * and p<sub>3</sub> (number of values per saw). The expression
+	 * (p<sub>3</sub>-p<sub>1</sub>)/p<sub>2</sub> must be truncated to integer to
+	 * start each saw curve cycle at p<sub>1</sub>.
+	 */
+	public static final SequenceRepresentation IMPLICIT_SAW = new SequenceRepresentation("IMPLICIT_SAW", 3);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub> for i &isin; [1, n], n is the total
+	 * number of values and generation parameters p<sub>1</sub> (offset),
+	 * p<sub>2</sub> (factor) and the raw value r at position i.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR = new SequenceRepresentation("RAW_LINEAR", 4);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> = &sum;
+	 * p<sub>j</sub>*r<sub>i</sub><sup>j-1</sup> = p<sub>2</sub>+p<sub>3
+	 * </sub>*r<sub>i</sub>+p<sub>4</sub>*r<sub>i</sub><sup>2</sup>+... for i &isin;
+	 * [1, n], n is the total number of values and generation parameters
+	 * p<sub>j</sub> for j &isin; [1, p<sub>1</sub>] and the raw value r at position
+	 * i.
+	 */
+	public static final SequenceRepresentation RAW_POLYNOMIAL = new SequenceRepresentation("RAW_POLYNOMIAL", 5);
+
+	/*
+	 * Not used. But keep here to show ordinal sequence.
+	 */
+	public static final SequenceRepresentation FORMULA = new SequenceRepresentation("FORMULA", 6);
+
+	/**
+	 * Measured values are stored as is in an external file and values are therefore
+	 * immediately available.
+	 */
+	public static final SequenceRepresentation EXPLICIT_EXTERNAL = new SequenceRepresentation("EXPLICIT_EXTERNAL", 7);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub> for i &isin; [1, n], n is the total
+	 * number of values and generation parameters p<sub>1</sub> (offset),
+	 * p<sub>2</sub> (factor) and the raw value r at position i read from an
+	 * external file.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR_EXTERNAL = new SequenceRepresentation("RAW_LINEAR_EXTERNAL",
+			8);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> = &sum;
+	 * p<sub>j</sub>*r<sub>i</sub><sup>j-1</sup> = p<sub>2</sub>+p<sub>3
+	 * </sub>*r<sub>i</sub>+p<sub>4</sub>*r<sub>i</sub><sup>2</sup>+... for i &isin;
+	 * [1, n], n is the total number of values and generation parameters
+	 * p<sub>j</sub> for j &isin; [1, p<sub>1</sub>] and the raw value r at position
+	 * i read from an external file.
+	 */
+	public static final SequenceRepresentation RAW_POLYNOMIAL_EXTERNAL = new SequenceRepresentation(
+			"RAW_POLYNOMIAL_EXTERNAL", 9);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * (p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub>)*p<sub>3</sub> for i &isin; [1,
+	 * n], n is the total number of values and generation parameters p<sub>1</sub>
+	 * (offset), p<sub>2</sub> (factor), p<sub>2</sub> (calibration) and the raw
+	 * value r at position i.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR_CALIBRATED = new SequenceRepresentation(
+			"RAW_LINEAR_CALIBRATED", 10);
+
+	/**
+	 * Each value x<sub>i</sub> is generated as follows: x<sub>i</sub> =
+	 * (p<sub>1</sub>+p<sub>2</sub>*r<sub>i</sub>)*p<sub>3</sub> for i &isin; [1,
+	 * n], n is the total number of values and generation parameters p<sub>1</sub>
+	 * (offset), p<sub>2</sub> (factor), p<sub>2</sub> (calibration) and the raw
+	 * value r at position i read from an external file.
+	 */
+	public static final SequenceRepresentation RAW_LINEAR_CALIBRATED_EXTERNAL = new SequenceRepresentation(
+			"RAW_LINEAR_CALIBRATED_EXTERNAL", 11);
+
+	private SequenceRepresentation(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #EXPLICIT}</li>
+	 * <li>{@link #EXPLICIT_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isExplicit() {
+		return name().startsWith("EXPLICIT");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #IMPLICIT_CONSTANT}</li>
+	 * <li>{@link #IMPLICIT_LINEAR}</li>
+	 * <li>{@link #IMPLICIT_SAW}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isImplicit() {
+		return name().startsWith("IMPLICIT");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #IMPLICIT_CONSTANT}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isConstant() {
+		return name().contains("CONSTANT");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #IMPLICIT_LINEAR}</li>
+	 * <li>{@link #RAW_LINEAR}</li>
+	 * <li>{@link #RAW_LINEAR_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isLinear() {
+		return name().contains("LINEAR");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #RAW_POLYNOMIAL}</li>
+	 * <li>{@link #RAW_POLYNOMIAL_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isPolynomial() {
+		return name().contains("POLYNOMIAL");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isCalibrated() {
+		return name().contains("CALIBRATED");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #EXPLICIT_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_EXTERNAL}</li>
+	 * <li>{@link #RAW_POLYNOMIAL_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isExternal() {
+		return name().endsWith("EXTERNAL");
+	}
+
+	/**
+	 * Returns true if this sequence representation is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #RAW_LINEAR}</li>
+	 * <li>{@link #RAW_POLYNOMIAL}</li>
+	 * <li>{@link #RAW_LINEAR_EXTERNAL}</li>
+	 * <li>{@link #RAW_POLYNOMIAL_EXTERNAL}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED}</li>
+	 * <li>{@link #RAW_LINEAR_CALIBRATED_EXTERNAL}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isRaw() {
+		return name().startsWith("RAW");
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Sortable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Sortable.java
new file mode 100644
index 0000000..f445a90
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Sortable.java
@@ -0,0 +1,69 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.Comparator;
+
+/**
+ * This interface extends the {@link Entity} interface and provides getter and
+ * setter methods for the 'SortIndex' field of an entity. The value in this
+ * field is the index of an entity relative to all other entities of the same
+ * type beneath their shared parent.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Sortable extends Entity {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * This {@code Comparator} compares entities implementing the {@link Sortable}
+	 * interface by the mandatory {@link #ATTR_SORT_INDEX} property in ascending
+	 * order.
+	 */
+	Comparator<Sortable> COMPARATOR = Comparator.comparing(Sortable::getSortIndex);
+
+	/**
+	 * The 'SortIndex' attribute name.
+	 */
+	String ATTR_SORT_INDEX = "Sortindex";
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the sort index of this entity.
+	 *
+	 * @return The sort index is returned.
+	 */
+	default Integer getSortIndex() {
+		return getValue(ATTR_SORT_INDEX).extract();
+	}
+
+	/**
+	 * Sets new sort index for this entity.
+	 *
+	 * @param sortIndex The new sort index.
+	 */
+	default void setSortIndex(Integer sortIndex) {
+		getValue(ATTR_SORT_INDEX).set(sortIndex);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/StatusAttachable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/StatusAttachable.java
new file mode 100644
index 0000000..10a612b
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/StatusAttachable.java
@@ -0,0 +1,30 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Each modeled {@link Entity} implements this interface to indicate that it has
+ * a status.
+ *
+ * <p>
+ * <b>Note:</b> State management is not part of the base application model.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface StatusAttachable extends Entity {
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Tagable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Tagable.java
new file mode 100644
index 0000000..57cabe3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Tagable.java
@@ -0,0 +1,27 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Each modeled {@link Entity} implements this interface to indicate that tags
+ * can be attached to it.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public interface Tagable extends Entity {
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Test.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Test.java
new file mode 100644
index 0000000..59641d2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Test.java
@@ -0,0 +1,122 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the test entity type. The test groups a number of single
+ * {@link TestStep}s. A measurement order always corresponds with exactly one
+ * test entity. The name of a test should be chosen in a speaking way, because
+ * it is often used in different contexts, e.g. as a link between the
+ * measurement data from the device and the order in the database. This type is
+ * a root node for persisted tests within a base application model. Extensions
+ * are free to introduce new entity types that may act as an immediate parent
+ * for entities of this type. In such cases tests have to be unique under the
+ * corresponding parent. Children of a test are {@code TestStep}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Test extends BaseEntity
+		implements Datable, Deletable, Describable, FilesAttachable, Tagable, StatusAttachable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link TestStep} child type.
+	 */
+	public static final Class<TestStep> CHILD_TYPE_TESTSTEP = TestStep.class;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Test(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@link User} who is responsible for this test.
+	 *
+	 * @return {@code Optional} is empty if the data source does not provide any
+	 *         {@code User} entities at all, which is implementation specific!
+	 */
+	public Optional<User> getResponsiblePerson() {
+		return Optional.ofNullable(getCore().getMutableStore().get(User.class));
+	}
+
+	/**
+	 * Sets new {@link User} as the responsible person for this test.
+	 *
+	 * @param responsiblePerson The new responsible person.
+	 */
+	public void setResponsiblePerson(User responsiblePerson) {
+		getCore().getMutableStore().set(responsiblePerson);
+	}
+
+	/**
+	 * Returns the commissioned {@link TestStep} identified by given name.
+	 *
+	 * @param name The name of the {@code TestStep}.
+	 * @return The {@code Optional} is empty if a {@code TestStep} with given name
+	 *         does not exist.
+	 */
+	public Optional<TestStep> getCommissionedTestStep(String name) {
+		return getCommissionedTestSteps().stream().filter(ts -> ts.nameEquals(name)).findAny();
+	}
+
+	/**
+	 * Returns all commissioned {@link TestStep}s related to this test.
+	 *
+	 * @return The returned {@code List} is unmodifiable.
+	 */
+	public List<TestStep> getCommissionedTestSteps() {
+		return getCore().getChildrenStore().get(TestStep.class);
+	}
+
+	/**
+	 * Removes the commissioned {@link TestStep} identified by given name.
+	 *
+	 * @param name Name of the {@code TestStep} that has to be removed.
+	 * @return Returns {@code true} if the {@code TestStep} with given name has been
+	 *         removed.
+	 */
+	public boolean removeCommissionedTestStep(String name) {
+		Optional<TestStep> testStep = getCommissionedTestStep(name);
+		if (testStep.isPresent()) {
+			getCore().getChildrenStore().remove(testStep.get());
+			return true;
+		}
+
+		return false;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TestStep.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TestStep.java
new file mode 100644
index 0000000..f1f46a2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TestStep.java
@@ -0,0 +1,129 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.BaseEntityManager;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+
+/**
+ * Implementation of the test step entity type. A test step is an atomic
+ * measurement task as part of a {@link Test}. The boundary conditions do not
+ * change within a single test step, therefore every ordered test step has to be
+ * fully described. It may have relations to {@link ContextRoot}s, which contain
+ * the describing order data. Test steps may have a sort order in the context of
+ * their parent {@code Test}, indicating the desired execution order. The name
+ * of a test step should be chosen in a speaking way, because it is often used
+ * in different contexts, e.g. as a link between the measurement data from the
+ * device and the order in the database. Furthermore the name has to be unique
+ * under the parent {@code Test}. Children of a test step are
+ * {@link Measurement}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class TestStep extends BaseEntity implements ContextDescribable, Datable, Deletable, Describable,
+		FilesAttachable, Sortable, StatusAttachable, Tagable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The {@link Test} parent type.
+	 */
+	public static final Class<Test> PARENT_TYPE_TEST = Test.class;
+
+	/**
+	 * The {@link Measurement} child type.
+	 */
+	public static final Class<Measurement> CHILD_TYPE_MEASUREMENT = Measurement.class;
+
+	/**
+	 * The 'Optional' attribute name.
+	 */
+	public static final String ATTR_OPTIONAL = "Optional";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	TestStep(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the optional flag of this test step.
+	 *
+	 * @return Returns the optional flag.
+	 */
+	public Boolean isOptional() {
+		return getValue(ATTR_OPTIONAL).extract();
+	}
+
+	/**
+	 * Sets new optional flag for this test step.
+	 *
+	 * @param optional The new optional flag.
+	 */
+	public void setOptional(Boolean optional) {
+		getValue(ATTR_OPTIONAL).set(optional);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public List<ContextType> loadContextTypes(BaseEntityManager manager) throws DataAccessException {
+		return manager.loadContextTypes(this);
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public Map<ContextType, ContextRoot> loadContexts(BaseEntityManager manager, ContextType... contextTypes)
+			throws DataAccessException {
+
+		Map<ContextType, ContextRoot> map = new HashMap<>();
+
+		for (ContextType contextType : contextTypes) {
+			ContextRoot c = getCore().getMutableStore().get(ContextRoot.class, contextType);
+			if (c != null) {
+				map.put(contextType, c);
+			}
+		}
+		if (map.isEmpty()) {
+			return manager.loadContexts(this, contextTypes);
+		} else {
+			return map;
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TypeSpecification.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TypeSpecification.java
new file mode 100644
index 0000000..3b9c70d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/TypeSpecification.java
@@ -0,0 +1,107 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * The type specification of mass data stored in external files.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Channel
+ */
+public class TypeSpecification extends EnumerationValue {
+
+	public static final TypeSpecification BOOLEAN = new TypeSpecification("BOOLEAN", 0);
+
+	public static final TypeSpecification BYTE = new TypeSpecification("BYTE", 1);
+
+	public static final TypeSpecification SHORT = new TypeSpecification("SHORT", 2);
+
+	public static final TypeSpecification INTEGER = new TypeSpecification("INTEGER", 3);
+
+	public static final TypeSpecification LONG = new TypeSpecification("LONG", 4);
+
+	public static final TypeSpecification FLOAT = new TypeSpecification("FLOAT", 5);
+
+	public static final TypeSpecification DOUBLE = new TypeSpecification("DOUBLE", 6);
+
+	public static final TypeSpecification SHORT_BEO = new TypeSpecification("SHORT_BEO", 7);
+
+	public static final TypeSpecification INTEGER_BEO = new TypeSpecification("INTEGER_BEO", 8);
+
+	public static final TypeSpecification LONG_BEO = new TypeSpecification("LONG_BEO", 9);
+
+	public static final TypeSpecification FLOAT_BEO = new TypeSpecification("FLOAT_BEO", 10);
+
+	public static final TypeSpecification DOUBLE_BEO = new TypeSpecification("DOUBLE_BEO", 11);
+
+	public static final TypeSpecification STRING = new TypeSpecification("STRING", 12);
+
+	public static final TypeSpecification BYTE_STREAM = new TypeSpecification("BYTE_STREAM", 13);
+
+	public static final TypeSpecification BLOB = new TypeSpecification("BLOB", 14);
+
+	public static final TypeSpecification BOOLEAN_FLAGS_BEO = new TypeSpecification("BOOLEAN_FLAGS_BEO", 15);
+
+	public static final TypeSpecification BYTE_FLAGS_BEO = new TypeSpecification("BYTE_FLAGS_BEO", 16);
+
+	public static final TypeSpecification STRING_FLAGS_BEO = new TypeSpecification("STRING_FLAGS_BEO", 17);
+
+	public static final TypeSpecification BYTE_STREAM_BEO = new TypeSpecification("BYTE_STREAM_BEO", 18);
+
+	// SBYTE,
+	public static final TypeSpecification SIGNED_BYTE = new TypeSpecification("SIGNED_BYTE", 19);
+
+	// SBYTE_FLAGS_BEO,
+	public static final TypeSpecification SIGNED_BYTE_FLAGS_BEO = new TypeSpecification("SIGNED_BYTE_FLAGS_BEO", 20);
+
+	// USHORT,
+	public static final TypeSpecification UNSIGNED_SHORT = new TypeSpecification("UNSIGNED_SHORT", 21);
+
+	// USHORT_BEO,
+	public static final TypeSpecification UNSIGNED_SHORT_BEO = new TypeSpecification("UNSIGNED_SHORT_BEO", 22);
+
+	// UINTEGER,
+	public static final TypeSpecification UNSIGNED_INTEGER = new TypeSpecification("UNSIGNED_INTEGER", 23);
+
+	// UINTEGER_BEO,
+	public static final TypeSpecification UNSIGNED_INTEGER_BEO = new TypeSpecification("UNSIGNED_INTEGER_BEO", 24);
+
+	public static final TypeSpecification STRING_UTF8 = new TypeSpecification("STRING_UTF8", 25);
+
+	public static final TypeSpecification STRING_UTF8_FLAGS_BEO = new TypeSpecification("STRING_UTF8_FLAGS_BEO", 26);
+
+	// BIT_INT,
+	public static final TypeSpecification BIT_INTEGER = new TypeSpecification("BIT_INTEGER", 27);
+
+	// BIT_INT_BEO,
+	public static final TypeSpecification BIT_INTEGER_BEO = new TypeSpecification("BIT_INTEGER_BEO", 28);
+
+	// BIT_UINT,
+	public static final TypeSpecification BIT_UNSIGNED_INTEGER = new TypeSpecification("BIT_UNSIGNED_INTEGER", 29);
+
+	// BIT_UINT_BEO,
+	public static final TypeSpecification BIT_UNSIGNED_INTEGER_BEO = new TypeSpecification("BIT_UNSIGNED_INTEGER_BEO",
+			30);
+
+	public static final TypeSpecification BIT_FLOAT = new TypeSpecification("BIT_FLOAT", 31);
+
+	public static final TypeSpecification BIT_FLOAT_BEO = new TypeSpecification("BIT_FLOAT_BEO", 32);
+
+	private TypeSpecification(String name, int ordinal) {
+		super(name, ordinal);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Unit.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Unit.java
new file mode 100644
index 0000000..ccf3bf3
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Unit.java
@@ -0,0 +1,170 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the unit entity type. Units referring to the same
+ * {@link PhysicalDimension} can be converted to each other by means of their
+ * attribute values "Offset" and "Factor". The names of the units have to be
+ * unique.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class Unit extends BaseEntity implements Datable, Deletable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Factor' attribute name.
+	 */
+	public static final String ATTR_FACTOR = "Factor";
+
+	/**
+	 * The 'Offset' attribute name.
+	 */
+	public static final String ATTR_OFFSET = "Offset";
+
+	/**
+	 * The 'DB' attribute name.
+	 */
+	public static final String ATTR_DB = "dB";
+
+	/**
+	 * The 'DBRreferenceFactor' attribute name.
+	 */
+	public static final String ATTR_DB_REFERENCE_FACTOR = "dB_reference_factor";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	Unit(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the factor of this unit.
+	 *
+	 * @return The factor is returned.
+	 */
+	public Double getFactor() {
+		return getValue(ATTR_FACTOR).extract();
+	}
+
+	/**
+	 * Sets new factor for this unit.
+	 *
+	 * @param factor The new factor.
+	 */
+	public void setFactor(Double factor) {
+		getValue(ATTR_FACTOR).set(factor);
+	}
+
+	/**
+	 * Returns the offset of this unit.
+	 *
+	 * @return The offset is returned.
+	 */
+	public Double getOffset() {
+		return getValue(ATTR_OFFSET).extract();
+	}
+
+	/**
+	 * Sets new offset for this unit.
+	 *
+	 * @param offset The new offset.
+	 */
+	public void setOffset(Double offset) {
+		getValue(ATTR_OFFSET).set(offset);
+	}
+
+	/**
+	 * Returns the decibel flag of this unit. If the flag is true, then
+	 * {@link #getDBRefFactor()} should return a finite value as returned by
+	 * {@link Float#isFinite(float)} that is not 0.
+	 *
+	 * @return True if this unit is a decibel unit.
+	 * @see #getDBRefFactor()
+	 */
+	public Boolean isDB() {
+		return getValue(ATTR_DB).extract();
+	}
+
+	/**
+	 * Returns the factor, which allows to convert the decibel values back into
+	 * linear values. If the decibel flag is set to false, this method should return
+	 * 0, which is described in the ASAM NVH specification (Chapter 11, 10.3).
+	 *
+	 * @return The decibel reference factor is returned.
+	 * @see #isDB()
+	 */
+	public Float getDBRefFactor() {
+		return getValue(ATTR_DB_REFERENCE_FACTOR).extract();
+	}
+
+	/**
+	 * Changes the decibel status of this unit. The decibel flag is deduced from
+	 * given reference factor. If the reference factor is finite, as returned by
+	 * {@link Float#isFinite(float)}, and not 0, then the decibel flag is set to
+	 * true and given reference factor is taken. In any other case both, the decibel
+	 * flag and the reference factor, will be reset.
+	 *
+	 * @param dbReferenceFactor The new decibel reference factor.
+	 */
+	public void setDB(Float dbReferenceFactor) {
+		boolean isValid = Float.isFinite(dbReferenceFactor) && Float.compare(Math.abs(dbReferenceFactor), 0F) != 0;
+		getValue(ATTR_DB).set(isValid);
+
+		if (isValid) {
+			getValue(ATTR_DB_REFERENCE_FACTOR).set(dbReferenceFactor);
+		} else {
+			getValue(ATTR_DB_REFERENCE_FACTOR).setValid(false);
+		}
+	}
+
+	/**
+	 * Returns the {@link PhysicalDimension} of this unit.
+	 *
+	 * @return The {@code PhysicalDimension} is returned.
+	 */
+	public PhysicalDimension getPhysicalDimension() {
+		return getCore().getMutableStore().get(PhysicalDimension.class);
+	}
+
+	/**
+	 * Sets new {@link PhysicalDimension} for this unit.
+	 *
+	 * @param physicalDimension The new {@code PhysicalDimension}.
+	 */
+	public void setPhysicalDimension(PhysicalDimension physicalDimension) {
+		getCore().getMutableStore().set(physicalDimension);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/User.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/User.java
new file mode 100644
index 0000000..531a945
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/User.java
@@ -0,0 +1,164 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+
+/**
+ * Implementation of the user entity type.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class User extends BaseEntity implements Deletable, Describable {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * The 'Surname' attribute name.
+	 */
+	public static final String ATTR_SURNAME = "Surname";
+
+	/**
+	 * The 'GivenName' attribute name.
+	 */
+	public static final String ATTR_GIVEN_NAME = "GivenName";
+
+	/**
+	 * The 'Department' attribute name.
+	 */
+	public static final String ATTR_DEPARTMENT = "Department";
+
+	/**
+	 * The 'Telephone' attribute name.
+	 */
+	public static final String ATTR_PHONE = "Telephone";
+
+	/**
+	 * The 'EMail' attribute name.
+	 */
+	public static final String ATTR_EMAIL = "E-Mail";
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param core The {@link Core}.
+	 */
+	User(Core core) {
+		super(core);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the given name of this user.
+	 *
+	 * @return The given name is returned.
+	 */
+	public String getGivenName() {
+		return getValue(ATTR_GIVEN_NAME).extract();
+	}
+
+	/**
+	 * Sets new given name for this user.
+	 *
+	 * @param givenName The new given name.
+	 */
+	public void setGivenName(String givenName) {
+		getValue(ATTR_GIVEN_NAME).set(givenName);
+	}
+
+	/**
+	 * Returns the surname of this user.
+	 *
+	 * @return The surname is returned.
+	 */
+	public String getSurname() {
+		return getValue(ATTR_SURNAME).extract();
+	}
+
+	/**
+	 * Sets new surname for this user.
+	 *
+	 * @param surname The new surname.
+	 */
+	public void setSurname(String surname) {
+		getValue(ATTR_SURNAME).set(surname);
+	}
+
+	/**
+	 * Returns the department of this user.
+	 *
+	 * @return The department is returned.
+	 */
+	public String getDepartment() {
+		return getValue(ATTR_DEPARTMENT).extract();
+	}
+
+	/**
+	 * Sets new department for this user.
+	 *
+	 * @param department The new department.
+	 */
+	public void setDepartment(String department) {
+		getValue(ATTR_DEPARTMENT).set(department);
+	}
+
+	/**
+	 * Returns the phone number of this user.
+	 *
+	 * @return The phone number is returned.
+	 */
+	public String getPhone() {
+		return getValue(ATTR_PHONE).extract();
+	}
+
+	/**
+	 * Sets new phone number for this user.
+	 *
+	 * @param phone The new phone number.
+	 */
+	public void setPhone(String phone) {
+		getValue(ATTR_PHONE).set(phone);
+	}
+
+	/**
+	 * Returns the e-mail address of this user.
+	 *
+	 * @return The e-mail address is returned.
+	 */
+	public String getMail() {
+		return getValue(ATTR_EMAIL).extract();
+	}
+
+	/**
+	 * Sets new e-mail address for this user.
+	 *
+	 * @param eMail The new e-mail address.
+	 */
+	public void setMail(String eMail) {
+		getValue(ATTR_EMAIL).set(eMail);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Value.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Value.java
new file mode 100644
index 0000000..05c02e5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/Value.java
@@ -0,0 +1,448 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static java.util.stream.IntStream.range;
+
+import java.lang.reflect.Array;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Generic value container. This value container is tightly coupled with its
+ * {@link ValueType}. It allows only to store assignment compatible values.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class Value {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	public static final DateTimeFormatter LOCAL_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
+
+	// ======================================================================
+	// Instances variables
+	// ======================================================================
+
+	private final ValueType<?> valueType;
+	private final String name;
+	private final String unit;
+
+	private boolean initialValid;
+	private Object initialValue;
+
+	private boolean valid;
+	private Object value;
+
+	private final Class<?> valueClass;
+	private final String valueTypeDescr;
+	private final Object defaultValue;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param valueType    The associated {@link ValueType}.
+	 * @param name         The name of this container.
+	 * @param unit         The name of the unit.
+	 * @param valid        The initial validity flag.
+	 * @param value        The initial value.
+	 * @param valueClass   Used for type checking upon assignment.
+	 * @param defaultValue Used as null replacement.
+	 */
+	Value(ValueType<?> valueType, String name, String unit, boolean valid, Object value, Class<?> valueClass,
+			Object defaultValue, String valueTypeDescr) {
+		this.valueType = valueType;
+		this.valueTypeDescr = valueTypeDescr;
+		this.name = name;
+		this.unit = unit == null ? "" : unit;
+
+		this.valueClass = valueClass;
+		this.defaultValue = defaultValue;
+
+		// set initial value
+		set(value);
+		// overwrite initial validity flag
+		setValid(valid);
+
+		// preserve initial values
+		initialValid = isValid();
+		initialValue = copy(extract());
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param origin The origin {@link Value}.
+	 * @param input  The new value.
+	 */
+	private Value(Value origin, Object input) {
+		this(origin.valueType, origin.name, origin.unit, origin.valid, input, origin.valueClass, origin.defaultValue,
+				origin.valueTypeDescr);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the name of this value container.
+	 *
+	 * @return This value container's name is returned.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * Returns the {@link ValueType} this value container is associated with.
+	 *
+	 * @return The associated {@code ValueType} is returned.
+	 */
+	public ValueType<?> getValueType() {
+		return valueType;
+	}
+
+	/**
+	 * Returns the unit name of this value container.
+	 *
+	 * @return The unit name of this value container is returned.
+	 */
+	public String getUnit() {
+		return unit;
+	}
+
+	/**
+	 * Returns the validity flag of this value container.
+	 *
+	 * @return True, if the stored value is marked to be valid.
+	 */
+	public boolean isValid() {
+		Object v = extract();
+
+		if (v != null) {
+			if (v.getClass().isArray()) {
+				return valid && Array.getLength(v) > 0;
+			} else if (v instanceof String) {
+				return valid && !((String) v).isEmpty();
+			}
+		}
+
+		return valid && v != null;
+	}
+
+	/**
+	 * Overwrites validity flag with given flag.
+	 *
+	 * @param valid The new validity flag.
+	 */
+	public void setValid(boolean valid) {
+		this.valid = valid;
+	}
+
+	/**
+	 * Returns currently stored value of this value container.
+	 *
+	 * @param <T>  The expected value type.
+	 * @param type The {@link ValueType}.
+	 * @return Currently stored value is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T> T extract(ValueType<T> type) {
+		return (T) value;
+	}
+
+	/**
+	 * Returns currently stored value of this value container.
+	 *
+	 * @param <T> The expected value type.
+	 * @return Currently stored value is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <T> T extract() {
+		return (T) value;
+	}
+
+	/**
+	 * Replaces currently stored value with the given one. If {@code null} is given,
+	 * then a well defined default value is used instead and the validity flag is
+	 * automatically set to {@code false}.
+	 *
+	 * @param input The new value must be an instance of the type defined in
+	 *              {@link ValueType#type} or in case of an enumeration type an
+	 *              appropriate enumeration constant or array thereof.
+	 * @throws IllegalArgumentException Thrown if an incompatible value is given.
+	 */
+	public void set(Object input) {
+		if (input == null) {
+			value = defaultValue;
+			setValid(false);
+		} else if (valueClass.isInstance(input)) {
+			value = input;
+			setValid(true);
+		} else if (input instanceof EnumerationValue) {
+			setForEnumerationValue(input);
+		} else {
+			throw new IllegalArgumentException("Incompatible value type '" + input.getClass().getSimpleName()
+					+ "' passed, expected '" + valueClass.getSimpleName() + "'.");
+		}
+	}
+
+	/**
+	 * Merges given value container with this instance. To be able to do so, the
+	 * given value container must be compatible with this one. Value containers are
+	 * compatible if the their name, unit and {@link ValueType} is equal. If the
+	 * stored values or the validity flags do not match, then both values are
+	 * discarded and {@code null} is taken as the initial value.
+	 *
+	 * @param value The value container that will be merged with this instance.
+	 * @return A new value container with merged value is returned.
+	 * @throws IllegalArgumentException Thrown if given value container is not
+	 *                                  compatible.
+	 */
+	public Value merge(Value value) {
+		boolean nameMissmatch = !getName().equals(value.getName());
+		boolean unitMissmatch = !getUnit().equals(value.getUnit());
+		boolean typeMissmatch = !getValueType().equals(value.getValueType());
+		if (nameMissmatch || unitMissmatch || typeMissmatch) {
+			throw new IllegalArgumentException("Unable to merge, incompatible value passed.");
+		}
+
+		boolean equalValue = Objects.deepEquals(extract(), value.extract());
+		boolean bothValid = isValid() && value.isValid();
+		return new Value(this, equalValue && bothValid ? extract() : null);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof Value)) {
+			return false;
+		}
+
+		Value val = (Value) other;
+
+		return Objects.equals(this.valueType, val.valueType) && Objects.equals(this.name, val.name)
+				&& Objects.equals(this.unit, val.unit) && Objects.equals(this.initialValid, val.initialValid)
+				&& Objects.deepEquals(this.initialValue, val.initialValue) && Objects.equals(this.valid, val.valid)
+				&& Objects.deepEquals(this.value, val.value) && Objects.equals(this.valueClass, val.valueClass)
+				&& Objects.equals(this.valueTypeDescr, val.valueTypeDescr)
+				&& Objects.equals(this.defaultValue, val.defaultValue);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(valueType, name, unit, initialValid, initialValue, valid, value, valueClass, valueTypeDescr,
+				defaultValue);
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this value. In case
+	 * of a sequence value container with up to 10 values the complete sequence will
+	 * be printed. Otherwise only the 5 first and last values will be printed. If
+	 * the contained value is marked as not valid, then the contained value is
+	 * omitted in the representation.
+	 *
+	 * @return The {@code String} representation of this value.
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder(name).append(" = ");
+
+		if (isValid()) {
+			Object v = extract();
+			if (v != null && v.getClass().isArray()) {
+				int length = Array.getLength(v);
+				sb.append('[');
+
+				if (length > 10) {
+					sb.append(range(0, 5).mapToObj(i -> readAt(v, i)).collect(Collectors.joining(", ")));
+					sb.append(", ..., ");
+					sb.append(range(length - 5, length).mapToObj(i -> readAt(v, i)).collect(Collectors.joining(", ")));
+				} else {
+					sb.append(range(0, length).mapToObj(i -> readAt(v, i)).collect(Collectors.joining(", ")));
+				}
+				sb.append(']');
+			} else {
+				sb.append(v);
+			}
+		}
+
+		if (!getUnit().isEmpty()) {
+			sb.append(" [").append(getUnit()).append(']');
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * Checks whether either the validity flag or the value have been modified since
+	 * initialization.
+	 *
+	 * @return Returns {@code true} either if the flag or the value has been
+	 *         modified.
+	 */
+	public boolean isModified() {
+		return wasValid() != isValid() || !Objects.deepEquals(extractInitial(), extract());
+	}
+
+	/**
+	 * Returns the initial validity flag.
+	 *
+	 * @return Returns {@code true} if the value was initially marked as valid.
+	 */
+	public boolean wasValid() {
+		return initialValid;
+	}
+
+	/**
+	 * Returns the initial value.
+	 *
+	 * @return The initial value is returned.
+	 */
+	public Object extractInitial() {
+		return initialValue;
+	}
+
+	/**
+	 * Overwrites the initial validity flag and value with the current ones.
+	 */
+	public void apply() {
+		initialValid = isValid();
+		initialValue = copy(extract());
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Returns the {@code String} value from given array at given position.
+	 *
+	 * @param array The array {@code Object}.
+	 * @param index The index of the required value.
+	 * @return The {@code String} value of the requested value is returned.
+	 */
+	static String readAt(Object array, int index) {
+		Object value = Array.get(array, index);
+		if (value != null && byte[].class.isInstance(value)) {
+			return Arrays.toString((byte[]) value);
+		}
+
+		return value == null ? "" : String.valueOf(value);
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * Returns a copy of given {@code Object}, so modifications in one do not affect
+	 * to other.
+	 *
+	 * @param value The object which will be copied.
+	 * @return The copy is returned.
+	 */
+	private static Object copy(Object value) {
+		if (value == null) {
+			return null;
+		}
+
+		Class<?> valueClass = value.getClass();
+		if (valueClass.isArray() && Array.getLength(value) > 0) {
+			return createDeepCopy(value, valueClass);
+		} else if (value instanceof FileLink) {
+			return new FileLink((FileLink) value);
+		}
+
+		// simple immutable value
+		return value;
+	}
+
+	/**
+	 * Replaces currently stored value with the given one.
+	 *
+	 * @param input The new value must be an instance of the enumeration type an
+	 *              appropriate enumeration constant.
+	 * @throws IllegalArgumentException Thrown if an incompatible value is given.
+	 */
+	private void setForEnumerationValue(Object input) {
+		String inpvalueTypeDescr = ((EnumerationValue) input).getOwner().getName();
+		if (inpvalueTypeDescr == null) {
+			throw new IllegalArgumentException(
+					"EnumerationValue value description of input value not correctly initialized");
+		}
+		if (valueTypeDescr == null) {
+			throw new IllegalArgumentException(
+					"EnumerationValue value description not correctly initialized got null, '" + "' expected '"
+							+ valueClass.getSimpleName() + "'.");
+		}
+
+		if (valueTypeDescr.equals(inpvalueTypeDescr)) {
+			value = input;
+			setValid(true);
+		} else {
+			throw new IllegalArgumentException("Incompatible value type description'" + inpvalueTypeDescr
+					+ "' passed, expected '" + valueTypeDescr + "'.");
+		}
+	}
+
+	/**
+	 * Returns a deep copy of given {@code Object}, so modifications in one do not
+	 * affect to other.
+	 *
+	 * @param value      The object which will be copied.
+	 * @param valueClass The class of the value object.
+	 * @return The copy is returned.
+	 */
+	private static Object createDeepCopy(Object value, Class<?> valueClass) {
+		int length = Array.getLength(value);
+
+		if (valueClass.getComponentType().isPrimitive()) {
+			Object copy = Array.newInstance(valueClass.getComponentType(), length);
+			System.arraycopy(value, 0, copy, 0, length);
+			return copy;
+		} else {
+			if (value instanceof byte[][]) {
+				return Arrays.stream((byte[][]) value).map(v -> v.clone()).toArray(byte[][]::new);
+			} else if (value instanceof FileLink[]) {
+				return Arrays.stream((FileLink[]) value).map(FileLink::new).toArray(FileLink[]::new);
+			} else {
+				return Arrays.copyOf((Object[]) value, length);
+			}
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ValueType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ValueType.java
new file mode 100644
index 0000000..5717b7e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/ValueType.java
@@ -0,0 +1,1038 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.time.LocalDateTime;
+
+/**
+ * Value type enumeration is a {@link Value} factory.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public class ValueType<T> extends EnumerationValue {
+
+	/**
+	 * A {@link Value} with this type contains a {@code String} value and replaces
+	 * {@code null} with an empty {@code String}.
+	 */
+	public static final ValueType<String> STRING = new ValueType<>(String.class, "STRING", "");
+
+	/**
+	 * A {@link Value} with this type contains a {@code String[]} value replaces
+	 * {@code null} with an empty {@code String} array.
+	 */
+	public static final ValueType<String[]> STRING_SEQUENCE = new ValueType<>(String[].class, "STRING_SEQUENCE",
+			new String[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link LocalDateTime} value and
+	 * does not replace {@code null}.
+	 */
+	public static final ValueType<LocalDateTime> DATE = new ValueType<>(LocalDateTime.class, "DATE", null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code LocalDateTime[]} value and
+	 * replaces {@code null} with an empty {@code LocalDateTime} array.
+	 */
+	public static final ValueType<LocalDateTime[]> DATE_SEQUENCE = new ValueType<>(LocalDateTime[].class,
+			"DATE_SEQUENCE", new LocalDateTime[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Boolean} value and replaces
+	 * {@code null} with {@link Boolean#FALSE}.
+	 */
+	public static final ValueType<Boolean> BOOLEAN = new ValueType<>(Boolean.class, "BOOLEAN", Boolean.FALSE);
+
+	/**
+	 * A {@link Value} with this type contains a {@code boolean[]} value and
+	 * replaces {@code null} with an empty {@code boolean} array.
+	 */
+	public static final ValueType<boolean[]> BOOLEAN_SEQUENCE = new ValueType<>(boolean[].class, "BOOLEAN_SEQUENCE",
+			new boolean[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Byte} value and replaces
+	 * {@code null} with a {@code Byte} containing zero.
+	 */
+	public static final ValueType<Byte> BYTE = new ValueType<>(Byte.class, "BYTE", Byte.valueOf((byte) 0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code byte[]} value and replaces
+	 * {@code null} with an empty {@code byte} array.
+	 */
+	public static final ValueType<byte[]> BYTE_SEQUENCE = new ValueType<>(byte[].class, "BYTE_SEQUENCE", new byte[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Short} value and replaces
+	 * {@code null} with a {@code Short} containing zero.
+	 */
+	public static final ValueType<Short> SHORT = new ValueType<>(Short.class, "SHORT", Short.valueOf((short) 0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code short[]} value and replaces
+	 * {@code null} with an empty {@code short} array.
+	 */
+	public static final ValueType<short[]> SHORT_SEQUENCE = new ValueType<>(short[].class, "SHORT_SEQUENCE",
+			new short[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Integer} value and replaces
+	 * {@code null} with a {@code Integer} containing zero.
+	 */
+	public static final ValueType<Integer> INTEGER = new ValueType<>(Integer.class, "INTEGER", Integer.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code int[]} value and replaces
+	 * {@code null} with an empty {@code int} array.
+	 */
+	public static final ValueType<int[]> INTEGER_SEQUENCE = new ValueType<>(int[].class, "INTEGER_SEQUENCE",
+			new int[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Long} value and replaces
+	 * {@code null} with a {@code Long} containing zero.
+	 */
+	public static final ValueType<Long> LONG = new ValueType<>(Long.class, "LONG", Long.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code long[]} value and replaces
+	 * {@code null} with an empty {@code long} array.
+	 */
+	public static final ValueType<long[]> LONG_SEQUENCE = new ValueType<>(long[].class, "LONG_SEQUENCE", new long[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Float} value and replaces
+	 * {@code null} with a {@code Float} containing zero.
+	 */
+	public static final ValueType<Float> FLOAT = new ValueType<>(Float.class, "FLOAT", Float.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code float[]} value and replaces
+	 * {@code null} with an empty {@code float} array.
+	 */
+	public static final ValueType<float[]> FLOAT_SEQUENCE = new ValueType<>(float[].class, "FLOAT_SEQUENCE",
+			new float[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Double} value and replaces
+	 * {@code null} with a {@code Double} containing zero.
+	 */
+	public static final ValueType<Double> DOUBLE = new ValueType<>(Double.class, "DOUBLE", Double.valueOf(0));
+
+	/**
+	 * A {@link Value} with this type contains a {@code double[]} value and replaces
+	 * {@code null} with an empty {@code double} array.
+	 */
+	public static final ValueType<double[]> DOUBLE_SEQUENCE = new ValueType<>(double[].class, "DOUBLE_SEQUENCE",
+			new double[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@code byte[]} value and replaces
+	 * {@code null} with an empty {@code byte} array.
+	 */
+	public static final ValueType<byte[]> BYTE_STREAM = new ValueType<>(byte[].class, "BYTE_STREAM", new byte[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@code byte[][]} value and replaces
+	 * {@code null} with an empty {@code byte[][]} array.
+	 */
+	public static final ValueType<byte[][]> BYTE_STREAM_SEQUENCE = new ValueType<>(byte[][].class,
+			"BYTE_STREAM_SEQUENCE", new byte[0][]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link FloatComplex} value and does
+	 * not replaces {@code null}.
+	 */
+	public static final ValueType<FloatComplex> FLOAT_COMPLEX = new ValueType<>(FloatComplex.class, "FLOAT_COMPLEX",
+			null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code FloatComplex[]} value and
+	 * replaces {@code null} with an empty {@code FloatComplex[]} array.
+	 */
+	public static final ValueType<FloatComplex[]> FLOAT_COMPLEX_SEQUENCE = new ValueType<>(FloatComplex[].class,
+			"FLOAT_COMPLEX_SEQUENCE", new FloatComplex[0]);
+
+	/**
+	 * A {@link Value} with this type contains a {@link DoubleComplex} value and
+	 * does not replaces {@code null}.
+	 */
+	public static final ValueType<DoubleComplex> DOUBLE_COMPLEX = new ValueType<>(DoubleComplex.class, "DOUBLE_COMPLEX",
+			null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code DoubleComplex[]} value and
+	 * replaces {@code null} with an empty {@code DoubleComplex[]} array.
+	 */
+	public static final ValueType<DoubleComplex[]> DOUBLE_COMPLEX_SEQUENCE = new ValueType<>(DoubleComplex[].class,
+			"DOUBLE_COMPLEX_SEQUENCE", new DoubleComplex[0]);
+
+	/**
+	 * A {@link Value} with this type contains a modeled enumeration constant value
+	 * and does not replace {@code null}.
+	 *
+	 */
+	public static final ValueType<EnumerationValue> ENUMERATION = new ValueType<>("ENUMERATION");
+
+	/**
+	 * A {@link Value} with this type contains a modeled enumeration constant array
+	 * value and replaces {@code null} with an empty array with defined component
+	 * type.
+	 *
+	 */
+	public static final ValueType<EnumerationValue[]> ENUMERATION_SEQUENCE = new ValueType<>("ENUMERATION_SEQUENCE");
+
+	/**
+	 * A {@link Value} with this type contains a {@link FileLink} value and does not
+	 * replace {@code null}.
+	 */
+	public static final ValueType<FileLink> FILE_LINK = new ValueType<>(FileLink.class, "FILE_LINK", null);
+
+	/**
+	 * A {@link Value} with this type contains a {@code FileLink[]} value and
+	 * replaces {@code null} with an empty {@code FileLink} array.
+	 */
+	public static final ValueType<FileLink[]> FILE_LINK_SEQUENCE = new ValueType<>(FileLink[].class,
+			"FILE_LINK_SEQUENCE", new FileLink[0]);
+
+	/**
+	 * TODO ...
+	 */
+	public static final ValueType<Object> BLOB = new ValueType<>(Object.class, "", null);
+
+	/**
+	 * A {@link Value} with this type contains a {@link Object} value and does not
+	 * replace {@code null}. This value type does not have a corresponding sequence
+	 * type.
+	 */
+	public static final ValueType<Object> UNKNOWN = new ValueType<>(Object.class, "UNKNOWN", null);
+
+	/**
+	 * The type is used to check assignment compatibility of non {@code null} values
+	 * passed to {@link Value#set(Object)}.
+	 */
+	private final Class<T> type;
+
+	/**
+	 * The default value will be used in {@link Value#set(Object)} to replace a
+	 * {@code null} input argument.
+	 */
+	private final T defaultValue;
+
+	/**
+	 * Constructor - May only be used to create {@link #ENUMERATION},
+	 * {@link #ENUMERATION_SEQUENCE} or {@link #UNKNOWN} types.
+	 * 
+	 * @param name
+	 */
+	private ValueType(String name) {
+		this(null, name, null);
+	}
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param type         The type of value a {@link Value} with this value type
+	 *                     will accept.
+	 * @param name
+	 * @param defaultValue Will be used as {@code null} replacement in
+	 *                     {@link Value#set(Object)}.
+	 */
+	private ValueType(Class<T> type, String name, T defaultValue) {
+		super(name);
+		this.type = type;
+		this.defaultValue = defaultValue;
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given name. The {@code
+	 * Value}'s initial validity flag will be set to {@code true}, the unit name
+	 * will be omitted.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code false}.
+	 *
+	 * @param name  The name of the attribute.
+	 * @param input The initial value.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Value create(String name, Object input) {
+		return create(name, "", true, input);
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given name. The {@code
+	 * Value}'s initial validity flag will be set to {@code false}, the unit name
+	 * will be omitted. The initial value will be the one defined in
+	 * {@link #defaultValue}.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code false}.
+	 *
+	 * @param name The name of the attribute.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Value create(String name) {
+		return create(name, "", false, defaultValue);
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given arguments.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code false}.
+	 *
+	 * @param name  The name of the attribute.
+	 * @param unit  The unit name of the attribute.
+	 * @param valid The initial validity flag.
+	 * @param input The initial value.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Value create(String name, String unit, boolean valid, Object input) {
+		if (isEnumerationType()) {
+			throw new IllegalStateException("This value type is an enumeration type.");
+		}
+
+		return new Value(this, name, unit, valid, input, type, defaultValue, null);
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given name. The {@code
+	 * Value}'s initial validity flag will be set to {@code false}, the unit name
+	 * will be omitted. The initial value will be {@code null} if
+	 * {@link #isSequence()} returns {@code false} otherwise an empty array with
+	 * given component type in enumClass is used.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code true}.
+	 *
+	 * @param <E>  Modeled enumeration type.
+	 * @param name The name of the attribute.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code false}.
+	 */
+	public <E extends EnumerationValue> Value create(Enumeration<E> enumObj, String name) {
+		return create(name, "", false, null, enumObj.getName());
+	}
+
+	/**
+	 * Creates a new {@link Value} initialized with given arguments.
+	 *
+	 * <p>
+	 * <b>Note:</b> This method is only allowed to be called where
+	 * {@link #isEnumerationType()} returns {@code true}.
+	 *
+	 * @param <E>   Modeled enumeration type.
+	 * @param name  The name of the attribute.
+	 * @param unit  The unit name of the attribute.
+	 * @param valid The initial validity flag.
+	 * @param input The initial value.
+	 * @return The created {@code Value} is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code false}.
+	 */
+	public <E extends EnumerationValue> Value create(String name, String unit, boolean valid, Object input,
+			String valueTypeDescr) {
+		if (isEnumerationType()) {
+			Object nullReplacement = null;
+			Class<?> valueClass = EnumerationValue.class;
+			if (isSequence()) {
+				nullReplacement = Array.newInstance(valueClass, 0);
+				valueClass = nullReplacement.getClass();
+			}
+
+			return new Value(this, name, unit, valid, input, valueClass, nullReplacement, valueTypeDescr);
+		}
+
+		throw new IllegalStateException("This value type is not an enumeration type.");
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #STRING}</li>
+	 * <li>{@link #STRING_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isStringType() {
+		return isString() || isStringSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #STRING}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isString() {
+		return STRING == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #STRING_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isStringSequence() {
+		return STRING_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #DATE}</li>
+	 * <li>{@link #DATE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isDateType() {
+		return isDate() || isDateSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DATE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDate() {
+		return DATE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DATE_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDateSequence() {
+		return DATE_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BOOLEAN}</li>
+	 * <li>{@link #BOOLEAN_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isBooleanType() {
+		return isBoolean() || isBooleanSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BOOLEAN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBoolean() {
+		return BOOLEAN == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BOOLEAN_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBooleanSequence() {
+		return BOOLEAN_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isNumericalType() {
+		return isAnyIntegerType() || isAnyFloatType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isAnyIntegerType() {
+		return isByteType() || isShortType() || isIntegerType() || isLongType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isByteType() {
+		return isByte() || isByteSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByte() {
+		return BYTE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteSequence() {
+		return BYTE_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #SHORT}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isShortType() {
+		return isShort() || isShortSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #SHORT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isShort() {
+		return SHORT == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #SHORT_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isShortSequence() {
+		return SHORT_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #INTEGER}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isIntegerType() {
+		return isInteger() || isIntegerSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #INTEGER}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isInteger() {
+		return INTEGER == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #INTEGER_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isIntegerSequence() {
+		return INTEGER_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #LONG}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isLongType() {
+		return isLong() || isLongSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #LONG}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLong() {
+		return LONG == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #LONG_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isLongSequence() {
+		return LONG_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isAnyFloatType() {
+		return isFloatType() || isDoubleType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFloatType() {
+		return isFloat() || isFloatSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloat() {
+		return FLOAT == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatSequence() {
+		return FLOAT_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #DOUBLE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isDoubleType() {
+		return isDouble() || isDoubleSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDouble() {
+		return DOUBLE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleSequence() {
+		return DOUBLE_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #BYTE_STREAM}</li>
+	 * <li>{@link #BYTE_STREAM_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isByteStreamType() {
+		return isByteStream() || isByteStreamSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE_STREAM}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteStream() {
+		return BYTE_STREAM == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BYTE_STREAM_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isByteStreamSequence() {
+		return BYTE_STREAM_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT_COMPLEX}</li>
+	 * <li>{@link #FLOAT_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE_COMPLEX}</li>
+	 * <li>{@link #DOUBLE_COMPLEX_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isComplexType() {
+		return isFloatComplexType() || isDoubleComplexType();
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FLOAT_COMPLEX}</li>
+	 * <li>{@link #FLOAT_COMPLEX_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFloatComplexType() {
+		return isFloatComplex() || isFloatComplexSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatComplex() {
+		return FLOAT_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FLOAT_COMPLEX_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFloatComplexSequence() {
+		return FLOAT_COMPLEX_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #DOUBLE_COMPLEX}</li>
+	 * <li>{@link #DOUBLE_COMPLEX_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isDoubleComplexType() {
+		return isDoubleComplex() || isDoubleComplexSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE_COMPLEX}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleComplex() {
+		return DOUBLE_COMPLEX == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #DOUBLE_COMPLEX_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isDoubleComplexSequence() {
+		return DOUBLE_COMPLEX_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #ENUMERATION}</li>
+	 * <li>{@link #ENUMERATION_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isEnumerationType() {
+		return isEnumeration() || isEnumerationSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #ENUMERATION}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEnumeration() {
+		return ENUMERATION == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #ENUMERATION_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEnumerationSequence() {
+		return ENUMERATION_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #FILE_LINK}</li>
+	 * <li>{@link #FILE_LINK_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isFileLinkType() {
+		return isFileLink() || isFileLinkSequence();
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FILE_LINK}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFileLink() {
+		return FILE_LINK == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #FILE_LINK_SEQUENCE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isFileLinkSequence() {
+		return FILE_LINK_SEQUENCE == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #BLOB}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isBlob() {
+		return BLOB == this;
+	}
+
+	/**
+	 * Returns true if this value type is {@link #UNKNOWN}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isUnknown() {
+		return UNKNOWN == this;
+	}
+
+	/**
+	 * Returns true if this value type is one of the following:
+	 *
+	 * <ul>
+	 * <li>{@link #STRING_SEQUENCE}</li>
+	 * <li>{@link #DATE_SEQUENCE}</li>
+	 * <li>{@link #BOOLEAN_SEQUENCE}</li>
+	 * <li>{@link #BYTE_SEQUENCE}</li>
+	 * <li>{@link #SHORT_SEQUENCE}</li>
+	 * <li>{@link #INTEGER_SEQUENCE}</li>
+	 * <li>{@link #LONG_SEQUENCE}</li>
+	 * <li>{@link #FLOAT_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE_SEQUENCE}</li>
+	 * <li>{@link #BYTE_STREAM_SEQUENCE}</li>
+	 * <li>{@link #FLOAT_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link #DOUBLE_COMPLEX_SEQUENCE}</li>
+	 * <li>{@link #ENUMERATION_SEQUENCE}</li>
+	 * <li>{@link #FILE_LINK_SEQUENCE}</li>
+	 * </ul>
+	 *
+	 * @return Returns {@code true} in the cases listed above.
+	 */
+	public boolean isSequence() {
+		return name() != null && name().endsWith("SEQUENCE");
+	}
+
+	/**
+	 * Returns the sequence version of this value type. This method returns itself,
+	 * if this value type is a sequence type.
+	 * 
+	 * If you extend the class ValueType, you have to ensure that T contains a field
+	 * of the correct name and type, otherwise a runtime error will occur.
+	 *
+	 * @return The sequence version of this value type is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <S extends ValueType<?>> S toSequenceType() {
+		if (isSequence()) {
+			return (S) this;
+		}
+
+		return (S) valueOf(name() + "_SEQUENCE");
+	}
+
+	/**
+	 * Returns the scalar version of this value type. This method returns itself, if
+	 * this value type is a scalar type.
+	 * 
+	 * If you extend the class ValueType, you have to ensure that T contains a field
+	 * of the correct name and type, otherwise a runtime error will occur.
+	 *
+	 * @return The sequence version of this value type is returned.
+	 */
+	@SuppressWarnings("unchecked")
+	public <S extends ValueType<?>> S toSingleType() {
+
+		if (isEnumerationType()) {
+			if (isSequence()) {
+				return (S) valueOf(name().replace("_SEQUENCE", ""));
+			}
+
+			return (S) this;
+		} else {
+			try {
+				if (isSequence()) {
+					Field field = getClass().getField(name().replace("_SEQUENCE", ""));
+					return (S) field.get(this);
+				}
+				return (S) this;
+			} catch (NoSuchFieldException | ClassCastException | IllegalAccessException e) {
+				throw new RuntimeException("Can't figure out single type for " + name());
+			}
+		}
+	}
+
+	/**
+	 * Returns the value class for this value type.
+	 *
+	 * @return The value class is returned.
+	 * @throws IllegalStateException Thrown if {@link #isEnumerationType()} returns
+	 *                               {@code true}.
+	 */
+	public Class<?> getValueClass() {
+		if (isEnumerationType()) {
+			throw new IllegalStateException("");
+		}
+		return type;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/VersionState.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/VersionState.java
new file mode 100644
index 0000000..6f2bdb5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/model/VersionState.java
@@ -0,0 +1,91 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+/**
+ * Version state enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see FileLink
+ */
+public class VersionState extends EnumerationValue {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * An entity with this version state is still editable and hence not allowed be
+	 * used when creating new entities.
+	 */
+	public static final VersionState EDITABLE = new VersionState("EDITABLE", 0);
+
+	/**
+	 * An entity with this version state is no longer editable and is allowed to be
+	 * used when creating new entities.
+	 *
+	 * <p>
+	 * <b>Note:</b> If an entity's version state is this state, then its version
+	 * state is only allowed to be changed to {@link #ARCHIVED}.
+	 */
+	public static final VersionState VALID = new VersionState("VALID", 1);
+
+	/**
+	 * An entity with this version state is neither editable nor is it allowed to
+	 * use it when creating new entities
+	 *
+	 * <p>
+	 * <b>Note:</b> If an entity's version state is this state, then its version
+	 * state is no longer allowed to be changed.
+	 */
+	public static final VersionState ARCHIVED = new VersionState("ARCHIVED", 2);
+
+	private VersionState(String name, int ordinal) {
+		super(name, ordinal);
+	}
+
+	/**
+	 * Returns true if this version state is {@link #EDITABLE}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isEditable() {
+		return EDITABLE == this;
+	}
+
+	/**
+	 * Returns true if this version state is {@link #VALID}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isValid() {
+		return VALID == this;
+	}
+
+	/**
+	 * Returns true if this version state is {@link #ARCHIVED}.
+	 *
+	 * @return Returns {@code true} if this constant is the constant described
+	 *         above.
+	 */
+	public boolean isArchived() {
+		return ARCHIVED == this;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationException.java
new file mode 100644
index 0000000..de97102
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationException.java
@@ -0,0 +1,46 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+/**
+ * Thrown to indicate a errors concerning notifications.
+ *
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public class NotificationException extends Exception {
+
+	private static final long serialVersionUID = 4011877631559261716L;
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The error message.
+	 */
+	public NotificationException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message   The error message.
+	 * @param throwable The origin cause.
+	 */
+	public NotificationException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationFilter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationFilter.java
new file mode 100644
index 0000000..4f6eb9a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationFilter.java
@@ -0,0 +1,81 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+
+/**
+ * Class represents a filter for notifications.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public class NotificationFilter {
+
+	/**
+	 * Modification type enumeration
+	 * 
+	 * @since 1.0.0
+	 * @author Matthias Koller, Peak Solution GmbH
+	 */
+	public static enum ModificationType {
+		INSTANCE_CREATED, INSTANCE_MODIFIED, INSTANCE_DELETED, MODEL_MODIFIED, SECURITY_MODIFIED;
+	}
+
+	private EnumSet<ModificationType> types = EnumSet.allOf(ModificationType.class);
+
+	private Set<EntityType> entityTypes = Collections.emptySet();
+
+	/**
+	 * Returns the {@link ModificationType}s of this filter.
+	 * 
+	 * @return Set with {@link ModificationType} is returned.
+	 */
+	public Set<ModificationType> getTypes() {
+		return types;
+	}
+
+	/**
+	 * Sets the {@link ModificationType}s used to filter the notifications.
+	 * 
+	 * @param types Set with {@link ModificationType}
+	 */
+	public void setTypes(Set<ModificationType> types) {
+		this.types = EnumSet.copyOf(types);
+	}
+
+	/**
+	 * Returns the {@link EntityType}s of this filter.
+	 * 
+	 * @return Set with {@link EntityType} is returned.
+	 */
+	public Set<EntityType> getEntityTypes() {
+		return entityTypes;
+	}
+
+	/**
+	 * Sets the {@link EntityType}s used to filter the notifications.
+	 * 
+	 * @param entityTypes Set with {@link EntityType}.
+	 */
+	public void setEntityTypes(Set<EntityType> entityTypes) {
+		this.entityTypes = new HashSet<>(entityTypes);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationListener.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationListener.java
new file mode 100644
index 0000000..a03a3d8
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationListener.java
@@ -0,0 +1,72 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.User;
+
+/**
+ * Listener interface for notifications.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public interface NotificationListener {
+	/**
+	 * Called when a new instance element was created by the server.
+	 * 
+	 * @param entities A list of newly created entities.
+	 * @param user     The user who created the entities.
+	 */
+	void instanceCreated(List<? extends Entity> entities, User user);
+
+	/**
+	 * Called when a existing instance element was modified by the server.
+	 * 
+	 * @param entities A list of modified entities.
+	 * @param user     The user who modified the entities.
+	 */
+	void instanceModified(List<? extends Entity> entities, User user);
+
+	/**
+	 * Called when a existing instance element was deleted by the server.
+	 * 
+	 * @param entityType EntityType of the deleted entities.
+	 * @param entities   A list with the IDs of deleted entities.
+	 * @param user       The user who deleted the entities.
+	 */
+	void instanceDeleted(EntityType entityType, List<String> ids, User user);
+
+	/**
+	 * Called when the application model is changed by the server
+	 * 
+	 * @param entityType Modified entityType.
+	 * @param user       The user who modified the application model.
+	 */
+	void modelModified(EntityType entityType, User user);
+
+	/**
+	 * Called when security related information is changed by the server
+	 * 
+	 * @param entityType EntityType with changed security
+	 * @param entities   A list with the IDs of entities related to the change.
+	 *                   Empty if change was only relevant for entityType.
+	 * @param user       The user who modified security information.
+	 */
+	void securityModified(EntityType entityType, List<String> ids, User user);
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationService.java
new file mode 100644
index 0000000..3f17478
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/notification/NotificationService.java
@@ -0,0 +1,56 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.notification;
+
+/**
+ * Manages registrations to a notification service.
+ * 
+ * @since 1.0.0
+ * @author Matthias Koller, Peak Solution GmbH
+ */
+public interface NotificationService {
+
+	/**
+	 * Registers a NotificationListener at the underlying notification service.
+	 * 
+	 * @param registrationName An unique name used for the registration.
+	 * @param filter           A notification filter, specifying which events should
+	 *                         be received by the listener.
+	 * @param listener         A notification listener which is informed if new
+	 *                         events are received.
+	 * @throws NotificationException In case the listener cannot be registered at
+	 *                               the notification service.
+	 */
+	void register(String registrationName, NotificationFilter filter, NotificationListener listener)
+			throws NotificationException;
+
+	/**
+	 * Unregisters a NotificationListener from the underlying notification service.
+	 * 
+	 * @param registrationName The unique name previously used for the registration.
+	 * @throws NotificationException In case the listener cannot be deregistered.
+	 */
+	void deregister(String registrationName) throws NotificationException;
+
+	/**
+	 * Closes the NotificationManager and all registered NotificationListeners
+	 * 
+	 * @param deregisterAll if true, all NotificationListeners are also deregistered
+	 *                      before closing.
+	 * @throws NotificationException In case the listeners cannot be deregistered or
+	 *                               the manager cannot be closed.
+	 */
+	void close(boolean deregisterAll) throws NotificationException;
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Aggregation.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Aggregation.java
new file mode 100644
index 0000000..cc4d733
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Aggregation.java
@@ -0,0 +1,83 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * Aggregation enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Query
+ */
+public enum Aggregation {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * No aggregate function is used for the selected attribute.
+	 */
+	NONE,
+
+	/**
+	 * Used to count the number of result rows.
+	 */
+	COUNT,
+
+	/**
+	 * Within the result rows for the selected attribute all distinct values are
+	 * counted.
+	 */
+	DISTINCT_COUNT,
+
+	/**
+	 * Within the result rows for the selected attribute the smallest value is
+	 * selected. Only for numerical values.
+	 */
+	MINIMUM,
+
+	/**
+	 * Within the result rows for the selected attribute the highest value is
+	 * selected. Only for numerical values.
+	 */
+	MAXIMUM,
+
+	/**
+	 * Over all result rows for the selected attribute the average value is
+	 * calculated. Only for numerical values.
+	 */
+	AVERAGE,
+
+	/**
+	 * Over all result rows for the selected attribute the standard deviation value
+	 * is calculated. Only for numerical values.
+	 */
+	DEVIATION,
+
+	/**
+	 * All result rows for the selected attribute are summed. Only for numerical
+	 * values.
+	 */
+	SUM,
+
+	/**
+	 * Within the result rows for the selected attribute all distinct values are
+	 * collected.
+	 */
+	DISTINCT
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BooleanOperator.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BooleanOperator.java
new file mode 100644
index 0000000..d92b9df
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BooleanOperator.java
@@ -0,0 +1,47 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * The operator enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Condition
+ * @see Filter
+ */
+public enum BooleanOperator {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Logical conjunction.
+	 */
+	AND,
+
+	/**
+	 * Logical disjunction.
+	 */
+	OR,
+
+	/**
+	 * Logical Negation.
+	 */
+	NOT
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BracketOperator.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BracketOperator.java
new file mode 100644
index 0000000..71070ca
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/BracketOperator.java
@@ -0,0 +1,52 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * The bracket operator enumeration.
+ *
+ * @since 1.0.0
+ * @see Condition
+ * @see Filter
+ */
+
+public enum BracketOperator {
+	/**
+	 * Left parenthesis.
+	 */
+	OPEN,
+
+	/**
+	 * Right parenthesis.
+	 */
+	CLOSE;
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Enum#toString()
+	 */
+	@Override
+	public String toString() {
+		switch (this) {
+		case OPEN:
+			return "(";
+		case CLOSE:
+			return ")";
+		default:
+			return this.toString();
+		}
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/ComparisonOperator.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/ComparisonOperator.java
new file mode 100644
index 0000000..f21710b
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/ComparisonOperator.java
@@ -0,0 +1,197 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Arrays;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+/**
+ * The selection operations define query instructions like "equal", "greater",
+ * etc. Such operations are case sensitive. If an insensitive instruction is
+ * required, then its counterpart starting with the "CI_" prefix has to be used.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Condition
+ * @see Filter
+ */
+public enum ComparisonOperator {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Exact match
+	 */
+	EQUAL,
+
+	/**
+	 * Not equal (!=)
+	 */
+	NOT_EQUAL,
+
+	/**
+	 * Less than (&lt;)
+	 */
+	LESS_THAN,
+
+	/**
+	 * Less than equal (&lt;=)
+	 */
+	LESS_THAN_OR_EQUAL,
+
+	/**
+	 * Greater than (&gt;)
+	 */
+	GREATER_THAN,
+
+	/**
+	 * Greater than equal (&gt;=)
+	 */
+	GREATER_THAN_OR_EQUAL,
+
+	/**
+	 * In set, value can be a sequence.
+	 */
+	IN_SET,
+
+	/**
+	 * Not in set, value can be a sequence.
+	 */
+	NOT_IN_SET,
+
+	/**
+	 * like, use pattern matching, see Pattern for the wildcard definitions.
+	 */
+	LIKE,
+
+	/**
+	 * Not LIKE
+	 */
+	NOT_LIKE,
+
+	/**
+	 * Equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_EQUAL,
+
+	/**
+	 * Not equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_NOT_EQUAL,
+
+	/**
+	 * Less than. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_LESS_THAN,
+
+	/**
+	 * Less than equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_LESS_THAN_OR_EQUAL,
+
+	/**
+	 * Greater than. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_GREATER_THAN,
+
+	/**
+	 * Greater than equal. case insensitive for {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_GREATER_THAN_OR_EQUAL,
+
+	/**
+	 * In set, value can be a sequence. case insensitive for
+	 * {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_IN_SET,
+
+	/**
+	 * Not in set, value can be a sequence. case insensitive for
+	 * {@link ValueType#STRING}
+	 */
+	CASE_INSENSITIVE_NOT_IN_SET,
+
+	/**
+	 * like, use pattern matching, see Pattern for the wildcard definitions. case
+	 * insensitive for DT_STRING.
+	 */
+	CASE_INSENSITIVE_LIKE,
+
+	/**
+	 * Not LIKE, case insensitive for DT_STRING.
+	 */
+	CASE_INSENSITIVE_NOT_LIKE,
+
+	/**
+	 * Value is NULL
+	 */
+	IS_NULL,
+
+	/**
+	 * Value is not NULL
+	 */
+	IS_NOT_NULL,
+
+	/**
+	 * Between; selects all instances where the value of 'attr' lies between the
+	 * first two values given in 'value' (with 'attr', 'value' being elements of the
+	 * SelValue structure; 'value' must be of data type S_*).
+	 */
+	BETWEEN;
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new {@link Condition} for given {@link Attribute} and value.
+	 *
+	 * @param attribute The {@code Attribute} the condition will be applied to.
+	 * @param value     The value.
+	 * @return The created {@code Condition} is returned.
+	 */
+	public Condition create(Attribute attribute, Object value) {
+		return new Condition(attribute, this, "", value);
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Checks whether this operation requires a sequence value container. This is
+	 * the case for the following types:
+	 *
+	 * <ul>
+	 * <li>{@link ComparisonOperator#IN_SET}</li>
+	 * <li>{@link ComparisonOperator#NOT_IN_SET}</li>
+	 * <li>{@link ComparisonOperator#CASE_INSENSITIVE_IN_SET}</li>
+	 * <li>{@link ComparisonOperator#CASE_INSENSITIVE_NOT_IN_SET}</li>
+	 * <li>{@link ComparisonOperator#BETWEEN}</li>
+	 * </ul>
+	 *
+	 * @return True if this operation is one of those listed above.
+	 */
+	boolean requiresSequence() {
+		return Arrays.asList(IN_SET, NOT_IN_SET, CASE_INSENSITIVE_IN_SET, CASE_INSENSITIVE_NOT_IN_SET, BETWEEN)
+				.contains(this);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Condition.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Condition.java
new file mode 100644
index 0000000..7b6c4f2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Condition.java
@@ -0,0 +1,131 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Objects;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * Describes a filter condition.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Attribute
+ * @see ComparisonOperator
+ */
+public final class Condition {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Attribute attribute;
+	private final Value value;
+	private final ComparisonOperator comparisonOperator;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param attribute          The {@link Attribute} this condition will be
+	 *                           applied to.
+	 * @param comparisonOperator The condition {@link ComparisonOperator}.
+	 * @param unit               The unit of the created value.
+	 * @param input              The condition value.
+	 */
+	Condition(Attribute attribute, ComparisonOperator comparisonOperator, String unit, Object input) {
+		this.attribute = attribute;
+		this.comparisonOperator = comparisonOperator;
+		value = comparisonOperator.requiresSequence() ? attribute.createValueSeq(unit, input)
+				: attribute.createValue(unit, input);
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the target {@link Attribute}.
+	 *
+	 * @return The target {@code Attribute} is returned.
+	 */
+	public Attribute getAttribute() {
+		return attribute;
+	}
+
+	/**
+	 * Returns the condition {@link Value}.
+	 *
+	 * @return The condition {@code Value} is returned.
+	 */
+	public Value getValue() {
+		return value;
+	}
+
+	/**
+	 * Returns the condition {@link ComparisonOperator}.
+	 *
+	 * @return The condition {@code ComparisonOperator} is returned.
+	 */
+	public ComparisonOperator getComparisonOperator() {
+		return comparisonOperator;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof Condition)) {
+			return false;
+		}
+
+		Condition condition = (Condition) other;
+
+		return Objects.equals(this.attribute, condition.attribute) && Objects.equals(this.value, condition.value)
+				&& Objects.equals(this.comparisonOperator, condition.comparisonOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(attribute, value, comparisonOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return attribute.getEntityType().getName() + "." + attribute.getName() + " " + comparisonOperator + " " + value;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/DataAccessException.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/DataAccessException.java
new file mode 100644
index 0000000..6848249
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/DataAccessException.java
@@ -0,0 +1,54 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * Thrown to indicate errors while querying data.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ */
+public final class DataAccessException extends RuntimeException {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	private static final long serialVersionUID = 5024184555274518451L;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message The error message.
+	 */
+	public DataAccessException(String message) {
+		super(message);
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param message   The error message.
+	 * @param throwable The origin cause.
+	 */
+	public DataAccessException(String message, Throwable throwable) {
+		super(message, throwable);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Filter.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Filter.java
new file mode 100644
index 0000000..010bc86
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Filter.java
@@ -0,0 +1,513 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.search.SearchQuery;
+import org.eclipse.mdm.api.base.search.SearchService;
+
+/**
+ * A filter is a sequence of {@link FilterItem}s containing
+ * {@link BooleanOperator}s or {@link Condition}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Query
+ * @see SearchQuery
+ * @see SearchService
+ */
+public final class Filter implements Iterable<FilterItem> {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Deque<FilterItem> filterItems = new ArrayDeque<>();
+	private final FilterItem operatorItem;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param operatorItem Will be added between {@link Condition}s or merged
+	 *                     filters.
+	 */
+	private Filter(FilterItem operatorItem) {
+		this.operatorItem = operatorItem;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Creates a new filter with an instance ID condition for given
+	 * {@link EntityType} and instance ID.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param id         The instance ID.
+	 * @return The created filter is returned.
+	 * @see #id(EntityType, String)
+	 */
+	public static Filter idOnly(EntityType entityType, String id) {
+		return and().id(entityType, id);
+	}
+
+	/**
+	 * Creates a new filter with an foreign ID condition for given {@link Relation}
+	 * and instance ID.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param id       The instance ID.
+	 * @return The created filter is returned.
+	 * @see #id(Relation, String)
+	 */
+	public static Filter idOnly(Relation relation, String id) {
+		return and().id(relation, id);
+	}
+
+	/**
+	 * Creates a new filter with an instance IDs condition for given
+	 * {@link EntityType} and instance IDs.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param ids        The instance IDs.
+	 * @return The created filter is returned.
+	 * @see #ids(EntityType, Collection)
+	 */
+	public static Filter idsOnly(EntityType entityType, Collection<String> ids) {
+		return and().ids(entityType, ids);
+	}
+
+	/**
+	 * Creates a new filter with an foreign IDs condition for given {@link Relation}
+	 * and instance IDs.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param ids      The instance IDs.
+	 * @return The created filter is returned.
+	 * @see #ids(Relation, Collection)
+	 */
+	public static Filter idsOnly(Relation relation, Collection<String> ids) {
+		return and().ids(relation, ids);
+	}
+
+	/**
+	 * Creates a new filter with an instance name condition for given
+	 * {@link EntityType} and instance name pattern.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param pattern    Is always case sensitive and may contain wildcard
+	 *                   characters as follows: "?" for one matching character and
+	 *                   "*" for a sequence of matching characters.
+	 * @return The created filter is returned.
+	 * @see #name(EntityType, String)
+	 */
+	public static Filter nameOnly(EntityType entityType, String pattern) {
+		return and().name(entityType, pattern);
+	}
+
+	/**
+	 * Creates a new instance of this class that implicitly adds
+	 * {@link BooleanOperator#AND} {@code FilterItem}s between {@link Condition}s or
+	 * merged filters.
+	 *
+	 * <pre>
+	 * Filter filter = Filter.and();
+	 * filter.add(conditionA); // conditionA
+	 * filter.add(conditionB); // conditionA AND conditionB
+	 * filter.invert(); // !(conditionA AND conditionB)
+	 * filter.merge(otherFilter); // !(conditionA AND conditionB) AND
+	 * 							// (otherFilter)
+	 * </pre>
+	 *
+	 * @return A newly created filter is returned.
+	 */
+	public static Filter and() {
+		return new Filter(FilterItem.AND);
+	}
+
+	/**
+	 * Creates a new instance of this class that implicitly adds
+	 * {@link BooleanOperator#OR} {@code FilterItem}s between {@link Condition}s or
+	 * merged filters.
+	 *
+	 * <pre>
+	 * Filter filter = Filter.or();
+	 * filter.add(conditionA); // conditionA
+	 * filter.add(conditionB); // conditionA OR conditionB
+	 * filter.invert(); // !(conditionA OR conditionB)
+	 * filter.merge(otherFilter); // !(conditionA OR conditionB) OR otherFilter
+	 * </pre>
+	 *
+	 * @return A newly created filter is returned.
+	 */
+	public static Filter or() {
+		return new Filter(FilterItem.OR);
+	}
+
+	/**
+	 * Adds all {@link Condition}s to this filter.
+	 *
+	 * @param conditions The {@link Condition}s that will be added.
+	 * @return Returns this filter.
+	 * @see Filter#add(Condition)
+	 */
+	public Filter addAll(List<Condition> conditions) {
+		conditions.forEach(this::add);
+		return this;
+	}
+
+	/**
+	 * Adds all {@link Condition}s to this filter.
+	 *
+	 * @param conditions The {@link Condition}s that will be added.
+	 * @return Returns this filter.
+	 * @see Filter#add(Condition)
+	 */
+	public Filter addAll(Condition... conditions) {
+		Arrays.stream(conditions).forEach(this::add);
+		return this;
+	}
+
+	/**
+	 * Adds a new instance ID condition ({@link ComparisonOperator#EQUAL}) for given
+	 * {@link EntityType} and instance ID to this filter.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param id         The instance ID.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter id(EntityType entityType, String id) {
+		add(ComparisonOperator.EQUAL.create(entityType.getIDAttribute(), id));
+		return this;
+	}
+
+	/**
+	 * Adds a new foreign ID condition ({@link ComparisonOperator#EQUAL}) for given
+	 * {@link Relation} and instance ID to this filter.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param id       The instance ID.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter id(Relation relation, String id) {
+		add(ComparisonOperator.EQUAL.create(relation.getAttribute(), id));
+		return this;
+	}
+
+	/**
+	 * Adds a new instance IDs condition ({@link ComparisonOperator#IN_SET}) for
+	 * given {@link EntityType} and instance IDs to this filter.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param ids        The instance IDs.
+	 * @return Returns this filter
+	 * @see #add(Condition)
+	 */
+	public Filter ids(EntityType entityType, Collection<String> ids) {
+		add(ComparisonOperator.IN_SET.create(entityType.getIDAttribute(),
+				ids.stream().distinct().toArray(String[]::new)));
+		return this;
+	}
+
+	/**
+	 * Adds a new foreign IDs condition ({@link ComparisonOperator#IN_SET}) for
+	 * given {@link Relation} and instance IDs to this filter.
+	 *
+	 * @param relation The {@code Relation}.
+	 * @param ids      The instance IDs.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter ids(Relation relation, Collection<String> ids) {
+		add(ComparisonOperator.IN_SET.create(relation.getAttribute(), ids.stream().distinct().toArray(String[]::new)));
+		return this;
+	}
+
+	/**
+	 * Adds a instance name condition ({@link ComparisonOperator#LIKE}) for given
+	 * {@link EntityType} and instance name pattern.
+	 *
+	 * <p>
+	 * <b>NOTE:</b> If the given pattern equals "*", then no {@link Condition} will
+	 * be added since "*" means take all.
+	 *
+	 * @param entityType The {@code EntityType}.
+	 * @param pattern    Is always case sensitive and may contain wildcard
+	 *                   characters as follows: "?" for one matching character and
+	 *                   "*" for a sequence of matching characters.
+	 * @return Returns this filter.
+	 * @see #add(Condition)
+	 */
+	public Filter name(EntityType entityType, String pattern) {
+		if (!"*".equals(pattern)) {
+			add(ComparisonOperator.LIKE.create(entityType.getNameAttribute(), pattern));
+		}
+		return this;
+	}
+
+	/**
+	 * Adds given {@link Condition} to this filter's {@link FilterItem} sequence.
+	 *
+	 * @param condition {@code Condition} that will be added.
+	 * @return Returns this filter.
+	 */
+	public Filter add(Condition condition) {
+		insertOperator();
+		filterItems.addLast(new FilterItem(condition));
+		return this;
+	}
+
+	/**
+	 * Merges all given filters with this filter.
+	 *
+	 * @param filters Filters that will be merged.
+	 * @return Returns this filter.
+	 * @see #merge(Filter)
+	 */
+	public Filter merge(List<Filter> filters) {
+		filters.stream().forEach(this::merge);
+		return this;
+	}
+
+	/**
+	 * Merges all given filters with this filter.
+	 *
+	 * @param filters Filters that will be merged.
+	 * @return Returns this filter.
+	 * @see #merge(Filter)
+	 */
+	public Filter merge(Filter... filters) {
+		Arrays.stream(filters).forEach(this::merge);
+		return this;
+	}
+
+	/**
+	 * The {@link FilterItem}s of the given filter are added to this filter. If
+	 * required, then parenthesis are implicitly added as shown in the example
+	 * below:
+	 *
+	 * <pre>
+	 * Filter filter1 = Filter.and();
+	 * Condition a = ...;
+	 * Condition b = ...;
+	 * filter1.addAll(a, b); // a AND b
+	 *
+	 * Filter filter2 = Filter.or();
+	 * Condition c = ...;
+	 * Condition d = ...;
+	 * Condition e = ...;
+	 * filter2.addAll(c, d, e); // c OR d OR e
+	 *
+	 * Filter filter = Filter.or();
+	 * filter.merge(filter1, filter2); // (filter1) OR filter2
+	 * </pre>
+	 *
+	 * @param filter Filter that will be merged.
+	 * @return Returns this filter.
+	 */
+	public Filter merge(Filter filter) {
+		boolean addBrackets = filter.hasMultiple() && operatorItem != filter.operatorItem && !filter.isInverted();
+		insertOperator();
+
+		if (addBrackets) {
+			filterItems.addLast(FilterItem.OPEN);
+		}
+
+		filter.filterItems.stream().forEach(filterItems::addLast);
+
+		if (addBrackets) {
+			filterItems.addLast(FilterItem.CLOSE);
+		}
+
+		return this;
+	}
+
+	/**
+	 * Inverts this filter by prepending the {@link BooleanOperator#NOT} to the
+	 * {@link FilterItem} sequence as shown in the following examples:
+	 *
+	 * <pre>
+	 * // inverting an AND filter
+	 * Filter andFilter = Filter.and();
+	 * Condition a = ...;      // any condition
+	 * Condition b = ...;      // another condition
+	 * andFilter.addAll(a, b); // a AND b
+	 * andFilter.invert();     // !(a AND b)
+	 *
+	 * // inverting an OR filter
+	 * Filter orFilter = Filter.or();
+	 * Condition a = ...;     // any condition
+	 * Condition b = ...;     // another condition
+	 * orFilter.addAll(a, b); // a OR b
+	 * orFilter.invert();     // !(a OR b)
+	 * orFilter.invert();     // IllegalStateException -&gt; filter is already inverted!
+	 * </pre>
+	 *
+	 * @return Returns this filter.
+	 * @throws IllegalStateException Thrown either if the current set of conditions
+	 *                               is empty or this filter is already inverted.
+	 */
+	public Filter invert() {
+		if (filterItems.isEmpty()) {
+			throw new IllegalStateException("Current set of conditions is empty.");
+		}
+
+		if (isInverted()) {
+			throw new IllegalStateException("Current set of conditions is already inverted.");
+		} else if (hasMultiple()) {
+			filterItems.addFirst(FilterItem.OPEN);
+			filterItems.addLast(FilterItem.CLOSE);
+		}
+
+		filterItems.addFirst(FilterItem.NOT);
+		return this;
+	}
+
+	/**
+	 * Checks whether this filter has no conditions at all.
+	 *
+	 * @return Returns {@code false} if at least one {@link Condition} is contained.
+	 */
+	public boolean isEmtpty() {
+		return filterItems.isEmpty();
+	}
+
+	/**
+	 * Returns a sequential stream with the internally stored {@link FilterItem}s as
+	 * its source.
+	 *
+	 * @return A stream over the contained {@code FilterItem}s is returned.
+	 */
+	public Stream<FilterItem> stream() {
+		return filterItems.stream();
+	}
+
+	/**
+	 * Returns an iterator over the {@link FilterItem}s contained in this filter in
+	 * proper sequence.
+	 *
+	 * @return The returned iterator does not support the {@link Iterator#remove()}
+	 *         operation.
+	 */
+	@Override
+	public Iterator<FilterItem> iterator() {
+		Iterator<FilterItem> internal = filterItems.iterator();
+		return new Iterator<FilterItem>() {
+
+			@Override
+			public boolean hasNext() {
+				return internal.hasNext();
+			}
+
+			@Override
+			public FilterItem next() {
+				return internal.next();
+			}
+		};
+	}
+
+	// ======================================================================
+	// Private methods
+	// ======================================================================
+
+	/**
+	 * If required the {@link #operatorItem} is added to the end (tail) of the
+	 * {@link FilterItem} sequence.
+	 */
+	private void insertOperator() {
+		if (!filterItems.isEmpty()) {
+			filterItems.addLast(operatorItem);
+		}
+	}
+
+	/**
+	 * Determines whether the {@link FilterItem} sequence starts with the
+	 * {@link BooleanOperator#NOT}.
+	 *
+	 * @return True if this filter is inverted.
+	 */
+	private boolean isInverted() {
+		return !filterItems.isEmpty() && FilterItem.NOT == filterItems.getFirst();
+	}
+
+	/**
+	 * Determines whether multiple {@link FilterItem}s are contained.
+	 *
+	 * @return True if multiple {@code FilterItem}s are contained.
+	 */
+	private boolean hasMultiple() {
+		return filterItems.size() > 1;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof Filter)) {
+			return false;
+		}
+
+		Filter filter = (Filter) other;
+
+		// Deque does not implement equals
+		return Arrays.equals(this.filterItems.toArray(new FilterItem[0]), filter.filterItems.toArray(new FilterItem[0]))
+				&& Objects.equals(this.operatorItem, filter.operatorItem);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(filterItems, operatorItem);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return this.stream().map(i -> Objects.toString(i)).collect(Collectors.joining(""));
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/FilterItem.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/FilterItem.java
new file mode 100644
index 0000000..a295626
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/FilterItem.java
@@ -0,0 +1,224 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Objects;
+
+/**
+ * Filter item contains either a {@link Condition} or an
+ * {@link BooleanOperator}.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class FilterItem {
+
+	// ======================================================================
+	// Class variables
+	// ======================================================================
+
+	/**
+	 * Contains the {@link BooleanOperator#AND}.
+	 */
+	static final FilterItem AND = new FilterItem(BooleanOperator.AND);
+
+	/**
+	 * Contains the {@link BooleanOperator#OR}.
+	 */
+	static final FilterItem OR = new FilterItem(BooleanOperator.OR);
+
+	/**
+	 * Contains the {@link BooleanOperator#NOT}.
+	 */
+	static final FilterItem NOT = new FilterItem(BooleanOperator.NOT);
+
+	/**
+	 * Contains the {@link BooleanOperator#OPEN}.
+	 */
+	static final FilterItem OPEN = new FilterItem(BracketOperator.OPEN);
+
+	/**
+	 * Contains the {@link BooleanOperator#CLOSE}.
+	 */
+	static final FilterItem CLOSE = new FilterItem(BracketOperator.CLOSE);
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Condition condition;
+	private final BooleanOperator booleanOperator;
+	private final BracketOperator bracketOperator;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param condition The {@link Condition}.
+	 */
+	FilterItem(Condition condition) {
+		this.condition = condition;
+		this.bracketOperator = null;
+		this.booleanOperator = null;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param booleanOperator The {@link BooleanOperator}.
+	 */
+	private FilterItem(BooleanOperator booleanOperator) {
+		this.condition = null;
+		this.bracketOperator = null;
+		this.booleanOperator = booleanOperator;
+	}
+
+	/**
+	 * Constructor.
+	 *
+	 * @param bracketoperator The {@link BracketOperator}.
+	 */
+	private FilterItem(BracketOperator bracketoperator) {
+		this.condition = null;
+		this.booleanOperator = null;
+		this.bracketOperator = bracketoperator;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Checks whether an {@link BooleanOperator} is contained.
+	 *
+	 * @return True if an {@code BooleanOperator} is contained.
+	 */
+	public boolean isBooleanOperator() {
+		return booleanOperator != null;
+	}
+
+	/**
+	 * Returns the contained {@link BooleanOperator}.
+	 *
+	 * @return The {@code BooleanOperator} is returned.
+	 * @throws IllegalStateException Thrown if {@code BooleanOperator} is not
+	 *                               contained.
+	 */
+	public BooleanOperator getBooleanOperator() {
+		if (isBooleanOperator()) {
+			return booleanOperator;
+		}
+
+		throw new IllegalStateException("Item does not contain an booleanOperator.");
+	}
+
+	/**
+	 * Checks whether an {@link Condition} is contained.
+	 *
+	 * @return True if an {@code Condition} is contained.
+	 */
+	public boolean isCondition() {
+		return condition != null;
+	}
+
+	/**
+	 * Returns the contained {@link Condition}.
+	 *
+	 * @return The {@code Condition} is returned.
+	 * @throws IllegalStateException Thrown if {@code Condition} is not contained.
+	 */
+	public Condition getCondition() {
+		if (isCondition()) {
+			return condition;
+		}
+
+		throw new IllegalStateException("Item does not contain a condition.");
+	}
+
+	/**
+	 * Checks whether an {@link BrackerOperator} is contained.
+	 *
+	 * @return True if an {@code BracketOperator} is contained.
+	 */
+	public boolean isBracketOperator() {
+		return bracketOperator != null;
+	}
+
+	/**
+	 * Returns the contained {@link Condition}.
+	 *
+	 * @return The {@code Condition} is returned.
+	 * @throws IllegalStateException Thrown if {@code Condition} is not contained.
+	 */
+	public BracketOperator getBracketOperator() {
+		if (isBracketOperator()) {
+			return bracketOperator;
+		}
+
+		throw new IllegalStateException("Item does not contain a condition.");
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object other) {
+		if (other == this) {
+			return true;
+		}
+		if (!(other instanceof FilterItem)) {
+			return false;
+		}
+
+		FilterItem filterItem = (FilterItem) other;
+
+		return Objects.equals(this.condition, filterItem.condition)
+				&& Objects.equals(this.booleanOperator, filterItem.booleanOperator)
+				&& Objects.equals(this.bracketOperator, filterItem.bracketOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		return Objects.hash(condition, booleanOperator, bracketOperator);
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		if (isBooleanOperator()) {
+			return " " + booleanOperator.toString() + " ";
+		} else if (isBracketOperator()) {
+			return bracketOperator.toString();
+		} else {
+			return condition.toString();
+		}
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/JoinType.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/JoinType.java
new file mode 100644
index 0000000..da92cdd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/JoinType.java
@@ -0,0 +1,41 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * JoinType enumeration.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Query
+ */
+public enum JoinType {
+
+	// ======================================================================
+	// Enumerations
+	// ======================================================================
+
+	/**
+	 * Enforces an inner join.
+	 */
+	INNER,
+
+	/**
+	 * Enforces an outer join.
+	 */
+	OUTER
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Query.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Query.java
new file mode 100644
index 0000000..058a363
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Query.java
@@ -0,0 +1,351 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+
+/**
+ * Provides methods to easily build queries by adding select, join, group by and
+ * order by statements. Finally an optional {@link Filter} may be given to
+ * select data that match specified criteria.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Attribute
+ * @see Aggregation
+ * @see Relation
+ * @see JoinType
+ * @see Result
+ */
+public interface Query {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Checks whether given {@link EntityType} will be queried in any way (select or
+	 * join).
+	 *
+	 * @param entityType The checked {@code EntityType}.
+	 * @return True if given {@code EntityType} will be queried.
+	 */
+	boolean isQueried(EntityType entityType);
+
+	/**
+	 * Adds select statements for all {@link Attribute}s of each given
+	 * {@link EntityType}.
+	 *
+	 * @param entityTypes The {@code Attribute}s of each {@code EntityType} will be
+	 *                    passed to {@link #select(List)}.
+	 * @return This query is returned.
+	 */
+	default Query selectAll(List<EntityType> entityTypes) {
+		entityTypes.stream().map(EntityType::getAttributes).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds select statements for all {@link Attribute}s of each given
+	 * {@link EntityType}.
+	 *
+	 * @param entityTypes The {@code Attribute}s of each {@code EntityType} will be
+	 *                    passed to {@link #select(List)}.
+	 * @return This query is returned.
+	 */
+	default Query selectAll(EntityType... entityTypes) {
+		Arrays.stream(entityTypes).map(EntityType::getAttributes).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds select statements for all {@link Attribute}s identified by given names
+	 * at given {@link EntityType}.
+	 *
+	 * @param entityType The {@code EntityType} whose {@code Attribute}s will be
+	 *                   passed to {@link #select(Attribute)}.
+	 * @param names      The names of the {@code Attribute}s that have to be added.
+	 * @return This query is returned.
+	 * @see EntityType#getAttribute(String)
+	 */
+	default Query select(EntityType entityType, String... names) {
+		Arrays.stream(names).map(entityType::getAttribute).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for the ID {@link Attribute} of each given
+	 * {@link EntityType}.
+	 *
+	 * @param entityTypes The {@code EntityType}s whose ID {@code Attribute}s will
+	 *                    be passed to {@link #select(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query selectID(EntityType... entityTypes) {
+		Arrays.stream(entityTypes).map(EntityType::getIDAttribute).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #select(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query select(List<Attribute> attributes) {
+		attributes.forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #select(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query select(Attribute... attributes) {
+		Arrays.stream(attributes).forEach(this::select);
+		return this;
+	}
+
+	/**
+	 * Adds a select statement for given {@link Attribute}.
+	 *
+	 * @param attribute {@code Attribute} will be passed to
+	 *                  {@link #select(Attribute, Aggregation)} with
+	 *                  {@link Aggregation#NONE}.
+	 * @return This query is returned.
+	 */
+	default Query select(Attribute attribute) {
+		return select(attribute, Aggregation.NONE);
+	}
+
+	/**
+	 * Adds a select statement for given {@link Attribute} with given
+	 * {@link Aggregation} function.
+	 *
+	 * @param attribute   The {@code Attribute} a select statement will be added
+	 *                    for.
+	 * @param aggregation The {@code Aggregation} that will be applied.
+	 * @return This query is returned.
+	 */
+	Query select(Attribute attribute, Aggregation aggregation);
+
+	/**
+	 * For all unambiguous {@link Relation}s from the source {@link EntityType} to
+	 * each given target {@code EntityType} a join statement will be added.
+	 *
+	 * @param source  The source {@code EntityType}.
+	 * @param targets The unambiguous {@code Relation} for each target {@code
+	 * 		EntityType} is retrieved from the source {@code EntityType} using
+	 *                {@link EntityType#getRelation(EntityType)} and passed to
+	 *                {@link #join(Relation)}.
+	 * @return This query is returned.
+	 */
+	default Query join(EntityType source, EntityType... targets) {
+		Arrays.stream(targets).map(source::getRelation).forEach(this::join);
+		return this;
+	}
+
+	/**
+	 * Adds a join statement for each given {@link Relation}s.
+	 *
+	 * @param relations Each {@code Relation} will be passed to
+	 *                  {@link #join(Relation)}.
+	 * @return This query is returned.
+	 */
+	default Query join(List<Relation> relations) {
+		relations.forEach(this::join);
+		return this;
+	}
+
+	/**
+	 * Adds a join statement for each given {@link Relation}s.
+	 *
+	 * @param relations Each {@code Relation} will be passed to
+	 *                  {@link #join(Relation)}.
+	 * @return This query is returned.
+	 */
+	default Query join(Relation... relations) {
+		Arrays.stream(relations).forEach(this::join);
+		return this;
+	}
+
+	/**
+	 * Adds a join statement for given {@link Relation}.
+	 *
+	 * @param relation {@code Relation} will be passed to
+	 *                 {@link #join(Relation, JoinType)} with
+	 *                 {@link JoinType#INNER}.
+	 * @return This query is returned.
+	 */
+	default Query join(Relation relation) {
+		return join(relation, JoinType.INNER);
+	}
+
+	/**
+	 * Adds a join statement for given {@link Relation} with given {@link JoinType}
+	 * type.
+	 *
+	 * @param relation The {@code Relation} a join statement will be added for.
+	 * @param join     The {@code JoinType} type that will be applied.
+	 * @return This query is returned.
+	 */
+	Query join(Relation relation, JoinType join);
+
+	/**
+	 * Adds a group by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #group(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query group(List<Attribute> attributes) {
+		attributes.forEach(this::group);
+		return this;
+	}
+
+	/**
+	 * Adds a group by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #group(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query group(Attribute... attributes) {
+		Arrays.stream(attributes).forEach(this::group);
+		return this;
+	}
+
+	/**
+	 * Adds a group by statement for given {@link Attribute}.
+	 *
+	 * @param attribute The {@code Attribute} a group by statement will be added
+	 *                  for.
+	 * @return This query is returned.
+	 */
+	Query group(Attribute attribute);
+
+	/**
+	 * Adds an order by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #order(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query order(List<Attribute> attributes) {
+		attributes.forEach(this::order);
+		return this;
+	}
+
+	/**
+	 * Adds an order by statement for each given {@link Attribute}.
+	 *
+	 * @param attributes Each {@code Attribute} will be passed to
+	 *                   {@link #order(Attribute)}.
+	 * @return This query is returned.
+	 */
+	default Query order(Attribute... attributes) {
+		Arrays.stream(attributes).forEach(this::order);
+		return this;
+	}
+
+	/**
+	 * Adds an order by statement for given {@link Attribute}.
+	 *
+	 * @param attribute The {@code Attribute} is passed to
+	 *                  {@link #order(Attribute, boolean)} with
+	 *                  {@code ascending = true}.
+	 * @return This query is returned.
+	 */
+	default Query order(Attribute attribute) {
+		return order(attribute, true);
+	}
+
+	/**
+	 * Adds an order by statement for given {@link Attribute} with given ascending
+	 * flag.
+	 *
+	 * @param attribute The {@code Attribute} an order by statement will be added
+	 *                  for.
+	 * @param ascending The ascending flag that will be applied.
+	 * @return This query is returned.
+	 */
+	Query order(Attribute attribute, boolean ascending);
+
+	/**
+	 * Sets the maximum number of rows fetched by the query. 0 denotes no limit.
+	 *
+	 * @param limit number of maximum rows.
+	 * @return This query is returned.
+	 */
+	Query limit(int limit);
+
+	/**
+	 * Executes this query with an empty {@link Filter} and returns the
+	 * {@link Result}.
+	 *
+	 * @return {@code Optional} is empty if {@code Result} could not be found.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}.
+	 */
+	default Optional<Result> fetchSingleton() throws DataAccessException {
+		return fetchSingleton(Filter.and());
+	}
+
+	/**
+	 * Executes this query with given {@link Filter} and returns the {@link Result}.
+	 *
+	 * @param filter The criteria sequence.
+	 * @return {@code Optional} is empty if {@code Result} could not be found.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}.
+	 */
+	Optional<Result> fetchSingleton(Filter filter) throws DataAccessException;
+
+	/**
+	 * Executes this query with an empty {@link Filter} and returns the
+	 * {@link Result}s.
+	 *
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 */
+	default List<Result> fetch() throws DataAccessException {
+		return fetch(Filter.and());
+	}
+
+	/**
+	 * Executes this query with given {@link Filter} and returns the
+	 * {@link Result}s.
+	 *
+	 * @param filter The criteria sequence.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 */
+	List<Result> fetch(Filter filter) throws DataAccessException;
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/QueryService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/QueryService.java
new file mode 100644
index 0000000..7d2ee5e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/QueryService.java
@@ -0,0 +1,34 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+/**
+ * The {@link QueryService} provides access to the low level query API.
+ * 
+ * A {@link Query}, created by this service, can be used to build and execute
+ * queries on the underlying datastore. The results are returned as a list of
+ * {@link Result}s.
+ *
+ * @since 1.0.0
+ */
+public interface QueryService {
+
+	/**
+	 * Creates a new and empty {@link Query}.
+	 *
+	 * @return Created {@code Query} is returned.
+	 */
+	Query createQuery();
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Record.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Record.java
new file mode 100644
index 0000000..0177dc6
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Record.java
@@ -0,0 +1,181 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * A record corresponds to an instance of the underlying {@link EntityType}. It
+ * contains a subset of its {@link Value}s.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see Attribute
+ */
+public final class Record {
+
+	// ======================================================================
+	// Instance variables
+	// ======================================================================
+
+	private final Map<String, Value> values = new HashMap<>();
+	private final EntityType entityType;
+
+	// ======================================================================
+	// Constructors
+	// ======================================================================
+
+	/**
+	 * Constructor.
+	 *
+	 * @param entityType The {@link EntityType} this record is associated with.
+	 */
+	public Record(EntityType entityType) {
+		this.entityType = entityType;
+	}
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns the associated {@link EntityType}.
+	 *
+	 * @return The associated {@code EntityType} is returned.
+	 */
+	public EntityType getEntityType() {
+		return entityType;
+	}
+
+	/**
+	 * Returns all contained {@link Value}s mapped by their names.
+	 *
+	 * @return Available {@code Value}s in a mutable {@code Map} are returned.
+	 */
+	public Map<String, Value> getValues() {
+		return values;
+	}
+
+	/**
+	 * Returns the record ID, which is the ID of the instance, represented by this
+	 * record.
+	 *
+	 * @return Returns the ID of this record.
+	 * @throws IllegalStateException Thrown if the ID {@code Value} container is not
+	 *                               available.
+	 */
+	public String getID() {
+		Value idValue = getValues().get(getEntityType().getIDAttribute().getName());
+		if (idValue == null) {
+			throw new IllegalStateException("ID attribute was not selected.");
+		}
+
+		return idValue.extract();
+	}
+
+	/**
+	 * Returns the instance ID of the related entity referenced by the given
+	 * {@link Relation}.
+	 *
+	 * @param relation The foreign key {@code Relation}.
+	 * @return {@code Optional} is empty if there is no related entity.
+	 * @throws IllegalStateException Thrown if the requested foreign key was not
+	 *                               selected prior executing the query.
+	 */
+	public Optional<String> getID(Relation relation) {
+		Value idValue = getValues().get(relation.getName());
+		if (idValue == null) {
+			throw new IllegalStateException("Relation attribute '" + relation + "' was not selected.");
+		}
+
+		return Optional.ofNullable(idValue.isValid() ? idValue.extract() : null);
+	}
+
+	/**
+	 * Adds given {@link Value} to this record.
+	 *
+	 * @param value {@link Value} that will be added.
+	 * @throws IllegalArgumentException Thrown if given {@code Value} overwrites an
+	 *                                  existing one.
+	 */
+	public void addValue(Value value) {
+		if (values.put(value.getName(), value) != null) {
+			throw new IllegalArgumentException("Value with name '" + value.getName() + "' for entity type '"
+					+ entityType + "' record is already defined.");
+		}
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this record.
+	 *
+	 * @return The {@code String} representation of this record.
+	 */
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder("Record(EntityType = ").append(getEntityType());
+		return sb.append(", Values = ").append(getValues().values()).append(')').toString();
+	}
+
+	// ======================================================================
+	// Package methods
+	// ======================================================================
+
+	/**
+	 * Merges given record with this instance. To be able to do so, the given record
+	 * must be compatible with this record. Records are compatible if the underlying
+	 * {@link EntityType} and the subset of {@link Value}s is the same.
+	 *
+	 * @param record The record that will be merged with this instance.
+	 * @return A new record with merged {@code Value}s is returned.
+	 * @throws IllegalArgumentException Thrown if given record is not compatible.
+	 */
+	Record merge(Record record) {
+		boolean entityTypeMissmatch = !getEntityType().equals(record.getEntityType());
+		boolean valuesMissmatch = getValues().size() != record.getValues().size();
+		if (entityTypeMissmatch || valuesMissmatch) {
+			throw new IllegalArgumentException("Unable to merge, incompatible record passed.");
+		}
+
+		Record mergedRecord = new Record(getEntityType());
+		getValues().keySet().stream().forEach(n -> mergedRecord.addValue(getValue(n).merge(record.getValue(n))));
+		return mergedRecord;
+	}
+
+	/**
+	 * Returns {@link Value} with given name.
+	 *
+	 * @param name Used as identifier.
+	 * @return {@code Value} with given name is returned.
+	 * @throws IllegalArgumentException Thrown if value with given name is not
+	 *                                  contained.
+	 */
+	Value getValue(String name) {
+		Value value = getValues().get(name);
+		if (value == null) {
+			throw new IllegalArgumentException("Value with name '" + name + "' not found.");
+		}
+
+		return value;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Result.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Result.java
new file mode 100644
index 0000000..8fb3e11
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/query/Result.java
@@ -0,0 +1,168 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * A result consists of one or more {@link Record}s, which is mapped from an
+ * {@link EntityType}
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ */
+public final class Result implements Iterable<Record> {
+
+	private final Map<EntityType, Record> records = new HashMap<>();
+
+	/**
+	 * Adds given {@link Record} to this result.
+	 *
+	 * @param record {@code Record} that will be added.
+	 * @throws IllegalArgumentException Thrown if given {@code Record} overwrites an
+	 *                                  existing one.
+	 */
+	public void addRecord(Record record) {
+		if (records.put(record.getEntityType(), record) != null) {
+			throw new IllegalArgumentException(
+					"Record for entity type '" + record.getEntityType() + "' is already defined.");
+		}
+	}
+
+	/**
+	 * Returns the {@link Record} associated with given {@link EntityType}.
+	 *
+	 * @param entityType Used as identifier.
+	 * @return The {@code Record} associated with given {@code EntityType} is
+	 *         returned.
+	 * @throws IllegalArgumentException Thrown if associated {@code Record} does not
+	 *                                  exist.
+	 */
+	public Record getRecord(EntityType entityType) {
+		Record record = records.get(entityType);
+		if (record == null) {
+			throw new IllegalArgumentException("Record for entity type '" + entityType + "' is not available.");
+		}
+
+		return record;
+	}
+
+	/**
+	 * Removes the {@link Record} associated with given {@link EntityType} from this
+	 * result and returns it.
+	 *
+	 * @param entityType Used as identifier.
+	 * @return The removed {@code Record} associated with given {@code EntityType}
+	 *         is returned.
+	 * @throws IllegalArgumentException Thrown if associated {@code Record} does not
+	 *                                  exists.
+	 */
+	public Record removeRecord(EntityType entityType) {
+		Record record = records.remove(entityType);
+		if (record == null) {
+			throw new IllegalArgumentException("Record for entity type '" + entityType + "' is not available.");
+		}
+
+		return record;
+	}
+
+	/**
+	 * Returns the {@link Value} container associated with given {@link Attribute}
+	 * and no aggregation.
+	 *
+	 * @param attribute Used as identifier to find the associated {@code Value}.
+	 * @return Associated {@code Value} is returned.
+	 */
+	public Value getValue(Attribute attribute) {
+		return getValue(attribute, Aggregation.NONE);
+	}
+
+	/**
+	 * Returns the {@link Value} container associated with given {@link Attribute}
+	 * and {@link Aggregation}.
+	 *
+	 * @param attribute   Used as identifier to find the associated {@code Value}.
+	 * @param aggregation {@link Aggregation} used with the attribute.
+	 * @return Associated {@code Value} is returned.
+	 */
+	public Value getValue(Attribute attribute, Aggregation aggregation) {
+		String key;
+		if (Aggregation.NONE == aggregation) {
+			key = attribute.getName();
+		} else {
+			key = String.format("%s(%s)", aggregation.name(), attribute.getName());
+		}
+
+		return getRecord(attribute.getEntityType()).getValue(key);
+	}
+
+	/**
+	 * Merges given result with this instance. To be able to do so, the given result
+	 * must be compatible with this result. Results are compatible if the subset of
+	 * {@link Record}s is the same.
+	 *
+	 * @param result The result that will be merged with this instance.
+	 * @return A new result with merged {@code Record}s is returned.
+	 * @throws IllegalArgumentException Thrown if given result is not compatible.
+	 */
+	public Result merge(Result result) {
+		if (records.size() != result.records.size()) {
+			throw new IllegalArgumentException("Unable to merge, incompatible result passed.");
+		}
+
+		Result mergedResult = new Result();
+		records.keySet().stream().forEach(e -> mergedResult.addRecord(getRecord(e).merge(result.getRecord(e))));
+		return mergedResult;
+	}
+
+	/**
+	 * Returns a sequential stream with this result as its source.
+	 *
+	 * @return A sequential stream with records of this result.
+	 */
+	public Stream<Record> stream() {
+		return StreamSupport.stream(spliterator(), false);
+	}
+
+	/**
+	 * Returns an iterator over the {@link Record}s contained in this result.
+	 *
+	 * @return The iterator over the contained {@code Record}s is returned.
+	 */
+	@Override
+	public Iterator<Record> iterator() {
+		return records.values().iterator();
+	}
+
+	/**
+	 * Returns a human readable {@code String} representation of this result.
+	 *
+	 * @return The {@code String} representation of this result.
+	 */
+	@Override
+	public String toString() {
+		return new StringBuilder("Result(Records = ").append(records.values()).append(')').toString();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchQuery.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchQuery.java
new file mode 100644
index 0000000..0a8b036
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchQuery.java
@@ -0,0 +1,171 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.search;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Result;
+
+/**
+ * This is an interface for predefined search query implementations.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Searchable
+ * @see Attribute
+ * @see Value
+ * @see Filter
+ * @see Result
+ */
+public interface SearchQuery {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns all {@link EntityType}s supported by this search query.
+	 *
+	 * @return The returned {@code List} may be immutable.
+	 */
+	List<EntityType> listEntityTypes();
+
+	/**
+	 * Returns the {@link Searchable}, which describes a hierarchical order of the
+	 * {@link EntityType}s supported by this search query.
+	 *
+	 * @return The {@code Searchable} root is returned.
+	 */
+	Searchable getSearchableRoot();
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute}. The
+	 * {@code Attribute} must be supported by this search query. The returned
+	 * {@code Value} sequence is intended to be used for building filter criteria
+	 * for this search query.
+	 *
+	 * @param attribute The {@code Attribute} whose distinct values will be queried.
+	 * @return A distinct {@code List} of all available {@code Value}s is returned.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the distinct {@code Value}
+	 *                             sequence.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #getFilterValues(Attribute, Filter)
+	 */
+	default List<Value> getFilterValues(Attribute attribute) throws DataAccessException {
+		return getFilterValues(attribute, Filter.and());
+	}
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute} and
+	 * {@link Filter}. Both must be fully supported by this search query. The
+	 * returned {@code Value} sequence is intended to be used for building filter
+	 * criteria for this search query.
+	 *
+	 * @param attribute The {@code Attribute} whose distinct values will be queried.
+	 * @param filter    The criteria sequence.
+	 * @return A distinct {@code List} of {@code Value}s is returned.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the distinct {@code Value}
+	 *                             sequence.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #getFilterValues(Attribute)
+	 */
+	List<Value> getFilterValues(Attribute attribute, Filter filter) throws DataAccessException;
+
+	/**
+	 * Executes this search query with given {@link EntityType}s. The {@code
+	 * EntityType}s must be fully supported by this search query. This method
+	 * selects all {@link Attribute}s of each given {@code EntityType}.
+	 *
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetchComplete(List, Filter)
+	 * @see #fetch(List)
+	 */
+	default List<Result> fetchComplete(List<EntityType> entityTypes) throws DataAccessException {
+		return fetchComplete(entityTypes, Filter.and());
+	}
+
+	/**
+	 * Executes this search query with given {@link EntityType}s and {@link Filter}.
+	 * Both must be fully supported by this search query. This method selects all
+	 * {@link Attribute}s of each given {@code EntityType}.
+	 *
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @param filter      The criteria sequence.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetchComplete(List)
+	 * @see #fetch(List, Filter)
+	 */
+	List<Result> fetchComplete(List<EntityType> entityTypes, Filter filter) throws DataAccessException;
+
+	/**
+	 * Executes this search query with given {@link Attribute}s. The {@code
+	 * Attribute}s must be fully supported by this search query. This method allows
+	 * fine grained {@link Result} configuration.
+	 *
+	 * @param attributes Select statements will be added for each {@code
+	 * 		Attribute}.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetch(List, Filter)
+	 * @see #fetchComplete(List)
+	 */
+	default List<Result> fetch(List<Attribute> attributes) throws DataAccessException {
+		return fetch(attributes, Filter.and());
+	}
+
+	/**
+	 * Executes this search query with given {@link Attribute}s and {@link Filter}.
+	 * Both must be fully supported by this search query. This method allows fine
+	 * grained {@link Result} configuration.
+	 *
+	 * @param attributes Select statements will be added for each {@code
+	 * 		Attribute}.
+	 * @param filter     The criteria sequence.
+	 * @return All {@code Result}s are returned in a {@code List}.
+	 * @throws DataAccessException Thrown in case of errors while executing the
+	 *                             query or generating the {@code Result}s.
+	 * @see #getSearchableRoot()
+	 * @see #listEntityTypes()
+	 * @see #fetch(List)
+	 * @see #fetchComplete(List, Filter)
+	 */
+	List<Result> fetch(List<Attribute> attributes, Filter filter) throws DataAccessException;
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchService.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchService.java
new file mode 100644
index 0000000..25c64cb
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/SearchService.java
@@ -0,0 +1,371 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.search;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.Value;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.eclipse.mdm.api.base.query.Filter;
+import org.eclipse.mdm.api.base.query.Record;
+import org.eclipse.mdm.api.base.query.Result;
+
+/**
+ * This search service uses given {@link Entity} type to execute the associated
+ * predefined {@link SearchQuery} and returns the results.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see EntityType
+ * @see Searchable
+ * @see Attribute
+ * @see Value
+ * @see Filter
+ * @see Result
+ */
+public interface SearchService {
+
+	/**
+	 * Returns all {@link Entity} types this search service provides a predefined
+	 * {@link SearchQuery} for.
+	 *
+	 * @return The returned {@code List} with supported types may be immutable.
+	 */
+	List<Class<? extends Entity>> listSearchableTypes();
+
+	/**
+	 * Returns all {@link EntityType}s supported by the {@link SearchQuery}
+	 * associated with given {@link Entity} type.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @return The returned {@code List} may be immutable.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 */
+	List<EntityType> listEntityTypes(Class<? extends Entity> entityClass);
+
+	/**
+	 * Returns the {@link Searchable}, which describes a hierarchical order of the
+	 * {@link EntityType}s supported by the {@link SearchQuery} associated with
+	 * given {@link Entity} type.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @return The {@code Searchable} root is returned.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 */
+	Searchable getSearchableRoot(Class<? extends Entity> entityClass);
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute}. The
+	 * {@code Attribute} must be supported by the {@link SearchQuery} associated
+	 * with given {@link Entity} type. The returned {@code Value} sequence is
+	 * intended to be used for building filter criteria.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attribute   The {@code Attribute} whose distinct values will be
+	 *                    queried.
+	 * @return A distinct {@code List} of all available {@code Value}s is returned.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  query or generating the distinct
+	 *                                  {@code Value} sequence.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #getFilterValues(Class, Attribute, Filter)
+	 */
+	default List<Value> getFilterValues(Class<? extends Entity> entityClass, Attribute attribute)
+			throws DataAccessException {
+		return getFilterValues(entityClass, attribute, Filter.and());
+	}
+
+	/**
+	 * Returns the distinct {@link Value} sequence for given {@link Attribute} and
+	 * {@link Filter}. Both must be fully supported by the {@link SearchQuery}
+	 * associated with given {@link Entity} type. The returned {@code Value}
+	 * sequence is intended to be used for building filter criteria.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attribute   The {@code Attribute} whose distinct values will be
+	 *                    queried.
+	 * @param filter      The criteria sequence.
+	 * @return A distinct {@code List} of {@code Value}s is returned.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  query or generating the distinct
+	 *                                  {@code Value} sequence.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #getFilterValues(Class, Attribute)
+	 */
+	List<Value> getFilterValues(Class<? extends Entity> entityClass, Attribute attribute, Filter filter)
+			throws DataAccessException;
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link EntityType}s.
+	 * The {@code EntityType}s must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method selects all
+	 * {@link Attribute}s of each given {@code EntityType}.
+	 *
+	 * It is only guaranteed that this method loads the selected entities, and their
+	 * relations among themselves. No information about additional related entities
+	 * is necessarily loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityCass  Used as the {@code SearchQuery} identifier.
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetch(Class, List)
+	 * @see Record#merge(Record)
+	 */
+	default <T extends Entity> List<T> fetchComplete(Class<T> entityCass, List<EntityType> entityTypes)
+			throws DataAccessException {
+		return fetchComplete(entityCass, entityTypes, Filter.and());
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link EntityType}s
+	 * and {@link Filter}. Both must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method selects all
+	 * {@link Attribute}s of each given {@code EntityType}.
+	 * 
+	 * It is only guaranteed that this method loads the selected entities, and their
+	 * relations among themselves. No information about additional related entities
+	 * is necessarily loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each.
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param entityTypes Select statements will be added for all {@code Attribute}s
+	 *                    of each given {@code EntityType}.
+	 * @param filter      The criteria sequence.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetch(Class, List, Filter)
+	 * @see Record#merge(Record)
+	 */
+	<T extends Entity> List<T> fetchComplete(Class<T> entityClass, List<EntityType> entityTypes, Filter filter)
+			throws DataAccessException;
+
+	/**
+	 * Executes the associated {@link SearchQuery} and returns all available
+	 * instances of the specified {@link Entity} type.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity, no
+	 * information about related entities is necessarily loaded.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @return All available entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #fetch(Class, Filter)
+	 */
+	default <T extends Entity> List<T> fetch(Class<T> entityClass) throws DataAccessException {
+		return fetch(entityClass, Filter.and());
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Filter}. The
+	 * {@code Filter} must be fully supported by the {@code SearchQuery} associated
+	 * with given {@link Entity} type. It is only guaranteed that this method loads
+	 * the selected entity, no information about related entities is necessarily
+	 * loaded.
+	 * 
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param filter      The criteria sequence.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetch(Class)
+	 */
+	default <T extends Entity> List<T> fetch(Class<T> entityClass, Filter filter) throws DataAccessException {
+		return fetch(entityClass, Collections.emptyList(), filter);
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Attribute}s.
+	 * The {@code Attribute}s must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method allows fine grained
+	 * {@link Record} configuration.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity or
+	 * attributes, no additional information about related entities is necessarily
+	 * loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attributes  Select statements will be added for each {@code
+	 * 		Attribute} .
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetchComplete(Class, List)
+	 * @see Record#merge(Record)
+	 */
+	default <T extends Entity> List<T> fetch(Class<T> entityClass, List<Attribute> attributes)
+			throws DataAccessException {
+		return fetch(entityClass, attributes, Filter.and());
+	}
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Attribute}s and
+	 * {@link Filter}. Both must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method allows fine grained
+	 * {@link Record} configuration.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity or
+	 * attributes, no additional information about related entities is necessarily
+	 * loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param <T>         Type of the entities that will be generated for each
+	 *                    result.
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attributes  Select statements will be added for each {@code
+	 * 		Attribute} .
+	 * @param filter      The criteria sequence.
+	 * @return All matched entities are returned in a {@code List}.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see #fetchComplete(Class, List, Filter)
+	 * @see Record#merge(Record)
+	 */
+	<T extends Entity> List<T> fetch(Class<T> entityClass, List<Attribute> attributes, Filter filter)
+			throws DataAccessException;
+
+	/**
+	 * Executes the associated {@link SearchQuery} with given {@link Attribute}s and
+	 * {@link Filter}. Both must be fully supported by the {@code SearchQuery}
+	 * associated with given {@link Entity} type. This method allows fine grained
+	 * {@link Record} configuration. This method allows to specify a fulltext search
+	 * query string.
+	 * 
+	 * It is only guaranteed that this method loads the selected entity or
+	 * attributes, no additional information about related entities is necessarily
+	 * loaded.
+	 *
+	 * <p>
+	 * <b>Note:</b> Related {@code Record}s may be merged according to the
+	 * cardinality of the associated {@link Relation}.
+	 *
+	 * @param entityClass Used as the {@code SearchQuery} identifier.
+	 * @param attributes  Select statements will be added for each {@code
+	 * 		Attribute} .
+	 * @param filter      The criteria sequence.
+	 * @param query       The fulltext search query
+	 * @return All {@link Result}s found by the {@link SearchQuery} with given
+	 *         {@link Attribute}s.
+	 * @throws DataAccessException      Thrown in case of errors while executing the
+	 *                                  {@code SearchQuery} or analyzing its
+	 *                                  {@code Result}s.
+	 * @throws IllegalArgumentException Thrown if given type is not associated with
+	 *                                  a predefined {@code SearchQuery}.
+	 * @see #listSearchableTypes()
+	 * @see #getSearchableRoot(Class)
+	 * @see #listEntityTypes(Class)
+	 * @see Record#merge(Record)
+	 */
+	default List<Result> fetchResults(Class<? extends Entity> entityClass, List<Attribute> attributes, Filter filter,
+			String query) throws DataAccessException {
+		throw new UnsupportedOperationException();
+	}
+
+	default boolean isTextSearchAvailable() {
+		return false;
+	}
+
+	@SuppressWarnings("unchecked")
+	default <T extends Entity> List<T> fetch(Class<T> entityClass, String query) throws DataAccessException {
+		return (List<T>) fetch(query).getOrDefault(entityClass, Collections.emptyList());
+	}
+
+	default Map<Class<? extends Entity>, List<Entity>> fetch(String query) throws DataAccessException {
+		throw new UnsupportedOperationException();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/Searchable.java b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/Searchable.java
new file mode 100644
index 0000000..f87c317
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/main/java/org/eclipse/mdm/api/base/search/Searchable.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.search;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.adapter.EntityType;
+
+/**
+ * A searchable is used to describe the hierarchical order of
+ * {@link EntityType}s being used for searching.
+ *
+ * @since 1.0.0
+ * @author Viktor Stoehr, Gigatronik Ingolstadt GmbH
+ * @author Sebastian Dirsch, Gigatronik Ingolstadt GmbH
+ * @see SearchService
+ * @see SearchQuery
+ */
+public interface Searchable {
+
+	// ======================================================================
+	// Public methods
+	// ======================================================================
+
+	/**
+	 * Returns all related searchables.
+	 *
+	 * @return Returned {@code List} may be immutable.
+	 */
+	List<Searchable> getRelatedSearchables();
+
+	/**
+	 * Returns the {@link EntityType} represented by this searchable.
+	 *
+	 * @return The {@code EntityType} represented by this searchable is returned.
+	 */
+	EntityType getEntityType();
+
+	/**
+	 * Returns {@code true} if this searchable doesn't have further related
+	 * searchables.
+	 *
+	 * @return True if this instance does not relate further searchables.
+	 */
+	default boolean isLeaf() {
+		return getRelatedSearchables().isEmpty();
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/AttributeImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/AttributeImpl.java
new file mode 100755
index 0000000..cb86c6d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/AttributeImpl.java
@@ -0,0 +1,63 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.model.Enumeration;
+import org.eclipse.mdm.api.base.model.ValueType;
+
+public class AttributeImpl implements Attribute {
+
+	public enum Type {
+		ID, UNKNOWN;
+	}
+
+	Type type;
+
+	public AttributeImpl(Type type) {
+		this.type = type;
+	}
+
+	@Override
+	public EntityType getEntityType() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public String getName() {
+		return type.name();
+	}
+
+	@Override
+	public String getUnit() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public ValueType getValueType() {
+		switch (type) {
+		case ID:
+			return ValueType.STRING;
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	@Override
+	public Enumeration<?> getEnumObj() {
+		throw new UnsupportedOperationException();
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/BaseEntityManagerTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/BaseEntityManagerTest.java
new file mode 100644
index 0000000..35a225b
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/BaseEntityManagerTest.java
@@ -0,0 +1,76 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.eclipse.mdm.api.base.model.TestStep;
+import org.eclipse.mdm.api.base.query.DataAccessException;
+import org.junit.Test;
+
+public class BaseEntityManagerTest {
+
+	@Test
+	public void loadShouldReturnEntity() throws DataAccessException {
+
+		@SuppressWarnings("unchecked")
+		BaseEntityManager entityManager = mock(BaseEntityManager.class);
+		TestStep mockedTestStep = mock(TestStep.class);
+
+		when(entityManager.load(any(), anyString())).thenCallRealMethod();
+		when(entityManager.load(TestStep.class, Arrays.asList("id1"))).thenReturn(Arrays.asList(mockedTestStep));
+
+		assertThat(entityManager.load(TestStep.class, "id1")).isEqualTo(mockedTestStep);
+	}
+
+	@Test
+	public void loadNotExistingIdShouldThrowDataAccessException() throws DataAccessException {
+
+		@SuppressWarnings("unchecked")
+		BaseEntityManager entityManager = mock(BaseEntityManager.class);
+
+		when(entityManager.load(any(), anyString())).thenCallRealMethod();
+		when(entityManager.load(eq(TestStep.class), anyCollection())).thenReturn(Collections.<TestStep>emptyList());
+
+		assertThatThrownBy(() -> entityManager.load(TestStep.class, "xyz")).isInstanceOf(DataAccessException.class)
+				.hasMessageContaining("Failed to load entity by instance ID.");
+	}
+
+	@Test
+	public void loadNotUniqueIdShouldThrowDataAccessException() throws DataAccessException {
+
+		@SuppressWarnings("unchecked")
+		BaseEntityManager entityManager = mock(BaseEntityManager.class);
+		TestStep mockedTestStep1 = mock(TestStep.class);
+		TestStep mockedTestStep2 = mock(TestStep.class);
+
+		when(entityManager.load(any(), anyString())).thenCallRealMethod();
+		when(entityManager.load(TestStep.class, Arrays.asList("id1")))
+				.thenReturn(Arrays.asList(mockedTestStep1, mockedTestStep2));
+
+		assertThatThrownBy(() -> entityManager.load(TestStep.class, "id1")).isInstanceOf(DataAccessException.class)
+				.hasMessageContaining("Failed to load entity by instance ID.");
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/CoreImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/CoreImpl.java
new file mode 100755
index 0000000..62bd195
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/CoreImpl.java
@@ -0,0 +1,99 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+import org.eclipse.mdm.api.base.adapter.RelationStore;
+import org.eclipse.mdm.api.base.model.Value;
+
+/**
+ * 
+ * Very basic implementation of the Core class. The contents is initialized via
+ * a given map (instead of using a database or some other method)
+ * 
+ * @author Florian Schmitt
+ */
+public class CoreImpl implements Core {
+
+	private Map<String, Value> values;
+	private EntityStore mutableStore;
+
+	public CoreImpl(Map<String, Value> values) {
+		super();
+		this.values = values;
+		this.mutableStore = new EntityStore();
+	}
+
+	@Override
+	public String getSourceName() {
+		return "UnitTestSource";
+	}
+
+	@Override
+	public String getTypeName() {
+		return "UnitTestType";
+	}
+
+	@Override
+	public String getID() {
+		return "4711l";
+	}
+
+	@Override
+	public void setID(String instanceID) {
+
+	}
+
+	@Override
+	public Map<String, Value> getValues() {
+		return values;
+	}
+
+	@Override
+	public void hideValues(Collection<String> names) {
+
+	}
+
+	@Override
+	public Map<String, Value> getAllValues() {
+		return values;
+	}
+
+	@Override
+	public EntityStore getMutableStore() {
+		return mutableStore;
+	}
+
+	@Override
+	public EntityStore getPermanentStore() {
+		return new EntityStore();
+	}
+
+	@Override
+	public ChildrenStore getChildrenStore() {
+		return new ChildrenStore();
+	}
+
+	@Override
+	public RelationStore getNtoMStore() {
+		return new RelationStore();
+	}
+
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityFactoryImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityFactoryImpl.java
new file mode 100755
index 0000000..b66eb08
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityFactoryImpl.java
@@ -0,0 +1,61 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.Optional;
+
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.model.BaseEntityFactory;
+import org.eclipse.mdm.api.base.model.ContextType;
+import org.eclipse.mdm.api.base.model.Entity;
+import org.eclipse.mdm.api.base.model.User;
+
+/**
+ * 
+ * Very basic implementation of BaseEntityFactory for testing purposes. We
+ * deliver a core containing data on initialization to simulate other data
+ * sources.
+ * 
+ * @author Florian Schmitt
+ *
+ */
+public class EntityFactoryImpl extends BaseEntityFactory {
+
+	private Core core;
+
+	public EntityFactoryImpl(Core core) {
+		this.core = core;
+	}
+
+	@Override
+	protected Optional<User> getLoggedInUser() {
+		return Optional.ofNullable(null);
+	}
+
+	@Override
+	protected <T extends Entity> Core createCore(Class<T> entityClass) {
+		return core;
+	}
+
+	@Override
+	protected <T extends Entity> Core createCore(Class<T> entityClass, ContextType contextType) {
+		return core;
+	}
+
+	@Override
+	protected <T extends Entity> Core createCore(String name, Class<T> entityClass) {
+		return core;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityTypeImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityTypeImpl.java
new file mode 100755
index 0000000..510e9f5
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/EntityTypeImpl.java
@@ -0,0 +1,92 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import java.util.List;
+
+import org.eclipse.mdm.api.base.AttributeImpl.Type;
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
+
+public class EntityTypeImpl implements EntityType {
+
+	@Override
+	public String getSourceName() {
+		return null;
+	}
+
+	@Override
+	public String getName() {
+		return null;
+	}
+
+	@Override
+	public String getId() {
+		return "0";
+	}
+
+	@Override
+	public List<Attribute> getAttributes() {
+		return null;
+	}
+
+	@Override
+	public Attribute getIDAttribute() {
+		return new AttributeImpl(Type.ID);
+	}
+
+	@Override
+	public Attribute getAttribute(String name) {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getParentRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getChildRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getInfoRelations() {
+		return null;
+	}
+
+	@Override
+	public List<Relation> getRelations(RelationType relationType) {
+		return null;
+	}
+
+	@Override
+	public Relation getRelation(EntityType target) {
+		return null;
+	}
+
+	@Override
+	public Relation getRelation(EntityType target, String name) {
+		return null;
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/RelationImpl.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/RelationImpl.java
new file mode 100755
index 0000000..ab4a632
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/RelationImpl.java
@@ -0,0 +1,78 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base;
+
+import org.eclipse.mdm.api.base.adapter.Attribute;
+import org.eclipse.mdm.api.base.adapter.EntityType;
+import org.eclipse.mdm.api.base.adapter.Relation;
+import org.eclipse.mdm.api.base.adapter.RelationType;
+
+public class RelationImpl implements Relation {
+
+	public enum AttributeType {
+		ID, UNKNOWN;
+	}
+
+	AttributeType type;
+
+	public RelationImpl(AttributeType type) {
+		this.type = type;
+	}
+
+	@Override
+	public String getName() {
+		return type.name();
+	}
+
+	@Override
+	public EntityType getSource() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public EntityType getTarget() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public RelationType getRelationType() {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public Attribute getAttribute() {
+		switch (type) {
+		case ID:
+			return new AttributeImpl(AttributeImpl.Type.ID);
+		default:
+			throw new UnsupportedOperationException();
+		}
+	}
+
+	@Override
+	public boolean isOutgoing(RelationType relationType) {
+		return true;
+	}
+
+	@Override
+	public boolean isIncoming(RelationType relationType) {
+		return false;
+	}
+
+	@Override
+	public boolean isNtoM() {
+		return false;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextComponentTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextComponentTest.java
new file mode 100644
index 0000000..cbee14a
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextComponentTest.java
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+
+public class ContextComponentTest {
+
+	@org.junit.Test
+	public void testGetContextRoot() {
+		BaseEntityFactory factory = spy(BaseEntityFactory.class);
+		Core rootCore = createCore("UNITUNDERTEST");
+		when(factory.createCore(ContextRoot.class, ContextType.UNITUNDERTEST)).thenReturn(rootCore);
+		Core componentCore = createCore("");
+		when(factory.createCore("Engine", ContextComponent.class)).thenReturn(componentCore);
+
+		ContextRoot contextRoot = factory.createContextRoot("Car", ContextType.UNITUNDERTEST);
+		ContextComponent contextComponent = factory.createContextComponent("Engine", contextRoot);
+
+		assertThat(contextComponent.getContextRoot()).isEqualTo(contextRoot);
+	}
+
+	private Core createCore(String type) {
+		Core core = mock(Core.class);
+
+		Map<String, Value> values = new HashMap<>();
+		values.put("Name", ValueType.STRING.create("Name"));
+		values.put("Version", ValueType.STRING.create("Version"));
+
+		when(core.getValues()).thenReturn(values);
+		when(core.getTypeName()).thenReturn(type);
+		when(core.getPermanentStore()).thenReturn(new EntityStore());
+		when(core.getChildrenStore()).thenReturn(new ChildrenStore());
+
+		return core;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextSensorTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextSensorTest.java
new file mode 100644
index 0000000..09ce5fd
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ContextSensorTest.java
@@ -0,0 +1,62 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.adapter.ChildrenStore;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.adapter.EntityStore;
+
+public class ContextSensorTest {
+
+	@org.junit.Test
+	public void testGetContextComponent() {
+		BaseEntityFactory factory = spy(BaseEntityFactory.class);
+		Core rootCore = createCore("TESTEQUIPMENT");
+		when(factory.createCore(ContextRoot.class, ContextType.TESTEQUIPMENT)).thenReturn(rootCore);
+		Core componentCore = createCore("");
+		when(factory.createCore("SensorDevice", ContextComponent.class)).thenReturn(componentCore);
+		Core sensorCore = createCore("");
+		when(factory.createCore("Sensor", ContextSensor.class)).thenReturn(sensorCore);
+
+		ContextRoot contextRoot = factory.createContextRoot("SensorDevices", ContextType.TESTEQUIPMENT);
+		ContextComponent contextComponent = factory.createContextComponent("SensorDevice", contextRoot);
+		ContextSensor contextSensor = factory.createContextSensor("Sensor", contextComponent);
+
+		assertThat(contextSensor.getContextComponent()).isEqualTo(contextComponent);
+	}
+
+	private Core createCore(String type) {
+		Core core = mock(Core.class);
+
+		Map<String, Value> values = new HashMap<>();
+		values.put("Name", ValueType.STRING.create("Name"));
+		values.put("Version", ValueType.STRING.create("Version"));
+
+		when(core.getValues()).thenReturn(values);
+		when(core.getTypeName()).thenReturn(type);
+		when(core.getPermanentStore()).thenReturn(new EntityStore());
+		when(core.getChildrenStore()).thenReturn(new ChildrenStore());
+
+		return core;
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ModelTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ModelTest.java
new file mode 100755
index 0000000..0b33be2
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ModelTest.java
@@ -0,0 +1,376 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.mdm.api.base.CoreImpl;
+import org.eclipse.mdm.api.base.EntityFactoryImpl;
+import org.eclipse.mdm.api.base.adapter.Core;
+import org.eclipse.mdm.api.base.massdata.UnitBuilder;
+import org.eclipse.mdm.api.base.massdata.WriteRequest;
+import org.eclipse.mdm.api.base.massdata.WriteRequestBuilder;
+import org.eclipse.mdm.api.base.model.MeasuredValues.ValueIterator;
+
+/**
+ * 
+ * some unit test to test functionality of org.eclipse.mdm.api.base.model. At
+ * this point, please don't expect anything near complete test coverage.
+ * 
+ * @author Florian Schmitt
+ *
+ */
+public class ModelTest {
+
+	// compare doubles up to this accuracy
+	private static final double EPSILON = 0.00005d;
+
+	/**
+	 * basic test for reading the value of a parameter.The intialization via maps is
+	 * needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void parameterValue() {
+		Map<String, Value> map = new HashMap<>();
+		map.put("DataType", new Value(ValueType.STRING, "DataType", null, true, ScalarType.FLOAT, ScalarType.class,
+				ScalarType.FLOAT, EnumRegistry.SCALAR_TYPE));
+		map.put("Value", ValueType.STRING.create("Value", null, true, "5.7"));
+		map.put("Name", ValueType.STRING.create("Name", null, true, "paramname"));
+		Core core = new CoreImpl(map);
+		Parameter tp = new Parameter(core);
+		Value vv = tp.getVirtualValue();
+		Float extracted = vv.extract();
+		assertEquals(5.7f, extracted, EPSILON);
+	}
+
+	/**
+	 * basic test for reading measured float values
+	 */
+	@org.junit.Test
+	public void measuredValueFloat() {
+		Float[] vals = { 1.0f, 2.0f, 3.7f, 2.1f };
+		boolean[] flags = { true, true, false, true };
+		MeasuredValues mv = new MeasuredValues(ScalarType.FLOAT, "Value1", "lightyears",
+				SequenceRepresentation.EXPLICIT, new double[0], false, AxisType.Y_AXIS, vals, flags);
+		ValueIterator<Float> valueIterator = mv.iterator();
+		int i = 0;
+		while (valueIterator.hasNext()) {
+			boolean isCurrentValid = valueIterator.isValid();
+			Float currentValue = valueIterator.next();
+			assertEquals(vals[i], currentValue, EPSILON);
+			assertEquals(flags[i], isCurrentValid);
+			i++;
+		}
+		assertEquals(i, vals.length);
+	}
+
+	/**
+	 * basic test for reading measured double values
+	 */
+	@org.junit.Test
+	public void measuredValueDouble() {
+		Double[] vals = { 1.0d, 2.0d, 3.7d, 2.1d };
+		boolean[] flags = { true, true, false, true };
+		MeasuredValues mv = new MeasuredValues(ScalarType.DOUBLE, "Value1", "lightyears",
+				SequenceRepresentation.EXPLICIT, new double[0], false, AxisType.Y_AXIS, vals, flags);
+		ValueIterator<Double> valueIterator = mv.iterator();
+		int i = 0;
+		while (valueIterator.hasNext()) {
+			boolean isCurrentValid = valueIterator.isValid();
+			Double currentValue = valueIterator.next();
+			assertEquals(vals[i], currentValue, EPSILON);
+			assertEquals(flags[i], isCurrentValid);
+			i++;
+		}
+		assertEquals(i, vals.length);
+	}
+
+	/**
+	 * basic test for reading measured string values
+	 */
+	@org.junit.Test
+	public void measuredValueString() {
+		String[] vals = { "str1", "str2", "str3", "str4" };
+		boolean[] flags = { true, true, false, true };
+		MeasuredValues mv = new MeasuredValues(ScalarType.STRING, "Value1", "lightyears",
+				SequenceRepresentation.EXPLICIT, new double[0], false, AxisType.Y_AXIS, vals, flags);
+		ValueIterator<String> valueIterator = mv.iterator();
+		int i = 0;
+		while (valueIterator.hasNext()) {
+			boolean isCurrentValid = valueIterator.isValid();
+			String currentValue = valueIterator.next();
+			assertEquals(vals[i], currentValue);
+			assertEquals(flags[i], isCurrentValid);
+			i++;
+		}
+		assertEquals(i, vals.length);
+	}
+
+	/**
+	 * basic test for reading attributes of the channel.The intialization via maps
+	 * is needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void getChannelAttrs() {
+		Map<String, Value> map = new HashMap<String, Value>();
+		float min_src = 5.7f;
+		float max_src = 10.23f;
+		map.put("Minimum", ValueType.DOUBLE.create("Minimum", "m/s", true, new Double(min_src)));
+		map.put("Maximum", ValueType.DOUBLE.create("Maximum", "m/s", true, new Double(max_src)));
+		Core core = new CoreImpl(map);
+		Channel ch = new Channel(core);
+		Double min = ch.getMinimum();
+		Double max = ch.getMaximum();
+		assertEquals(min, min_src, EPSILON);
+		assertEquals(max, max_src, EPSILON);
+	}
+
+	/**
+	 * basic test to read the default scalar type of a quantity. The intialization
+	 * via maps is needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void getQuantity() {
+		Map<String, Value> map = new HashMap<String, Value>();
+		map.put("DefDataType", new Value(ValueType.ENUMERATION, "name", "unit", true, ScalarType.FLOAT,
+				ScalarType.class, ScalarType.FLOAT, EnumRegistry.SCALAR_TYPE));
+		Core core = new CoreImpl(map);
+		Quantity quantity = new Quantity(core);
+		ScalarType defaultScalarType = quantity.getDefaultScalarType();
+		assertTrue(defaultScalarType.isFloat());
+	}
+
+	/**
+	 * basic test for building a write request
+	 */
+	@org.junit.Test
+	public void writeRequest() {
+		AxisType axisType = AxisType.X_AXIS;
+		Core core = new CoreImpl(new HashMap<>());
+		ChannelGroup channelGroup = new ChannelGroup(core);
+		Channel channel = new Channel(core);
+		WriteRequestBuilder wrb = WriteRequest.create(channelGroup, channel, axisType);
+		UnitBuilder ub = wrb.implicitConstant(ScalarType.DOUBLE, 0.7d);
+		WriteRequest wr = ub.build();
+		SequenceRepresentation sequenceRepresentation = wr.getSequenceRepresentation();
+		assertTrue(sequenceRepresentation.isConstant());
+		assertEquals(AxisType.X_AXIS, wr.getAxisType());
+	}
+
+	/**
+	 * basic test for getting a measurement channel and all necessary related
+	 * objects (measurment, and so on) via factory methods. The intialization via
+	 * maps is needed to simulate the data store.
+	 */
+	@org.junit.Test
+	public void entityFactory() {
+		Map<String, Value> map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, "pdnameabc"));
+		map.put("Length", ValueType.INTEGER.create("Length", null, true, 13));
+		map.put("Mass", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("Time", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("Temperature", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("Current", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("MolarAmount", ValueType.INTEGER.create("Length", null, true, 0));
+		map.put("LuminousIntensity", ValueType.INTEGER.create("Length", null, true, 0));
+		// TODO (Florian Schmitt): check if angle in lower case is correct
+		map.put("angle", ValueType.INTEGER.create("Length", null, true, 0));
+		Core core = new CoreImpl(map);
+		EntityFactoryImpl ef = new EntityFactoryImpl(core);
+		PhysicalDimension physicalDimension = ef.createPhysicalDimension("physdim");
+
+		map = new HashMap<String, Value>();
+		map.put("Offset", ValueType.DOUBLE.create("Length", null, true, 0d));
+		map.put("Factor", ValueType.DOUBLE.create("Length", null, true, 0d));
+		map.put("Name", ValueType.STRING.create("Name", null, true, "unitname"));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Unit unit = ef.createUnit("unit", physicalDimension);
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, "quantname"));
+		map.put("Version", ValueType.STRING.create("Version", null, true, "4711"));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		map.put("DefaultRank", ValueType.INTEGER.create("DefaultRank", null, true, 5));
+		map.put("DefDimension", ValueType.INTEGER_SEQUENCE.create("DefDimension", null, true, new int[] { 5 }));
+		map.put("DefTypeSize", ValueType.INTEGER.create("DefTypeSize", null, true, 8));
+		map.put("DefMQName", ValueType.STRING.create("DefMQName", null, true, "mqname"));
+		map.put("DefDataType", new Value(ValueType.ENUMERATION, "DefDataType", "", true, ScalarType.DOUBLE,
+				ScalarType.class, ScalarType.DOUBLE, EnumRegistry.SCALAR_TYPE));
+		map.put("ValidFlag", new Value(ValueType.ENUMERATION, "ValidFlag", "", false, VersionState.ARCHIVED,
+				VersionState.class, null, EnumRegistry.VERSION_STATE));
+		map.put("Description", ValueType.STRING.create("Description", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Quantity quantity = ef.createQuantity("quantity", unit);
+		// Note that default values are set in createQuantity and thus should
+		// differ from above.
+		assertEquals(ScalarType.FLOAT, quantity.getDefaultScalarType());
+		assertEquals((Integer) 1, quantity.getDefaultRank());
+		assertEquals("quantity", quantity.getName());
+		assertEquals(unit, quantity.getDefaultUnit());
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Test test = ef.createTest("mytest");
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		map.put("Optional", ValueType.BOOLEAN.create("Optional", null, true, null));
+		map.put("Sortindex", ValueType.INTEGER.create("Sortindex", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		TestStep testStep = ef.createTestStep("teststep", test);
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("DateCreated", ValueType.DATE.create("DateCreated", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Measurement measurement = ef.createMeasurement("measurement", testStep);
+
+		map = new HashMap<String, Value>();
+		map.put("Name", ValueType.STRING.create("Name", null, true, null));
+		map.put("Description", ValueType.STRING.create("Description", null, true, null));
+		map.put("Interpolation", new Value(ValueType.ENUMERATION, "Interpolation", "", true, null, Interpolation.class,
+				null, EnumRegistry.SCALAR_TYPE));
+		map.put("DataType", new Value(ValueType.ENUMERATION, "DataType", "", true, null, ScalarType.class, null,
+				EnumRegistry.SCALAR_TYPE));
+
+		map.put("TypeSize", ValueType.INTEGER.create("TypeSize", null, true, null));
+		map.put("Rank", ValueType.INTEGER.create("Rank", null, true, null));
+		core = new CoreImpl(map);
+		ef = new EntityFactoryImpl(core);
+		Channel channel = ef.createChannel("channel", measurement, quantity);
+		assertEquals(Interpolation.NONE, channel.getInterpolation());
+	}
+
+	/**
+	 * basic test of some ValuType methods.
+	 */
+	@org.junit.Test
+	public void valueType() {
+		EnumRegistry.getInstance();
+		assertEquals(ValueType.SHORT_SEQUENCE.toSingleType(), ValueType.SHORT);
+		assertEquals(ValueType.DATE.toSequenceType(), ValueType.DATE_SEQUENCE);
+		assertEquals(ValueType.ENUMERATION_SEQUENCE.toSingleType(), ValueType.ENUMERATION);
+		assertEquals(ValueType.ENUMERATION.toSingleType(), ValueType.ENUMERATION);
+		assertEquals(ValueType.ENUMERATION, ValueType.ENUMERATION.valueOf(ValueType.ENUMERATION.toSingleType().name()));
+		assertEquals(Float.class, ValueType.FLOAT.getValueClass());
+		assertEquals(true, ValueType.DOUBLE.isAnyFloatType());
+		assertEquals(true, ValueType.DOUBLE.isDouble());
+		assertEquals(false, ValueType.DOUBLE.isFloat());
+		assertEquals(true, ValueType.FLOAT.isAnyFloatType());
+		assertEquals(false, ValueType.INTEGER.isAnyFloatType());
+		assertEquals(true, ValueType.INTEGER.isInteger());
+		assertEquals(false, ValueType.FLOAT.isInteger());
+		assertEquals(true, ValueType.FLOAT.isFloat());
+	}
+
+	/**
+	 * basic tests of some ScalarType methods
+	 */
+	@org.junit.Test
+	public void scalarType() {
+		assertEquals(ValueType.BYTE_SEQUENCE, ScalarType.BYTE.toValueType());
+		assertEquals(true, ScalarType.LONG.isLong());
+		assertEquals(false, ScalarType.DOUBLE_COMPLEX.isLong());
+	}
+
+	/**
+	 * basic test of some SequenceReprestentaion methods
+	 */
+	@org.junit.Test
+	public void sequenceRepresentation() {
+		assertNotEquals(SequenceRepresentation.EXPLICIT, SequenceRepresentation.IMPLICIT_CONSTANT);
+		assertTrue(SequenceRepresentation.EXPLICIT.isExplicit());
+		assertTrue(SequenceRepresentation.EXPLICIT_EXTERNAL.isExplicit());
+		assertTrue(SequenceRepresentation.EXPLICIT_EXTERNAL.isExternal());
+		assertFalse(SequenceRepresentation.EXPLICIT_EXTERNAL.isImplicit());
+		assertEquals(SequenceRepresentation.EXPLICIT.ordinal(), (Integer) 0);
+		assertEquals((Integer) 5, SequenceRepresentation.RAW_POLYNOMIAL.ordinal());
+		assertEquals((Integer) 7, SequenceRepresentation.EXPLICIT_EXTERNAL.ordinal());
+		assertEquals((Integer) 9, SequenceRepresentation.RAW_POLYNOMIAL_EXTERNAL.ordinal());
+		assertEquals((Integer) 10, SequenceRepresentation.RAW_LINEAR_CALIBRATED.ordinal());
+		assertEquals((Integer) 11, SequenceRepresentation.RAW_LINEAR_CALIBRATED_EXTERNAL.ordinal());
+	}
+
+	/**
+	 * basic tests of TypeSpecification
+	 */
+	@org.junit.Test
+	public void typeSpecification() {
+		assertNotEquals(TypeSpecification.BIT_INTEGER, TypeSpecification.BIT_FLOAT_BEO);
+		assertEquals(TypeSpecification.BOOLEAN, TypeSpecification.BOOLEAN);
+	}
+
+	/**
+	 * basic tests of AxisTzpe methods
+	 */
+	@org.junit.Test
+	public void axisType() {
+		assertTrue(AxisType.X_AXIS.isXAxis());
+		assertTrue(AxisType.Y_AXIS.isYAxis());
+		assertTrue(AxisType.XY_AXIS.isXYAxis());
+		assertFalse(AxisType.X_AXIS.isYAxis());
+		assertFalse(AxisType.Y_AXIS.isXYAxis());
+		assertFalse(AxisType.XY_AXIS.isXAxis());
+	}
+
+	/**
+	 * basic tests of VersionState enumeration
+	 */
+	@org.junit.Test
+	public void versionState() {
+		assertFalse(VersionState.ARCHIVED.isEditable());
+		assertTrue(VersionState.ARCHIVED.isArchived());
+		assertFalse(VersionState.ARCHIVED.isValid());
+		assertTrue(VersionState.EDITABLE.isEditable());
+		assertFalse(VersionState.EDITABLE.isArchived());
+		assertFalse(VersionState.EDITABLE.isValid());
+		assertFalse(VersionState.VALID.isEditable());
+		assertFalse(VersionState.VALID.isArchived());
+		assertTrue(VersionState.VALID.isValid());
+	}
+
+	/**
+	 * basic tests of interpolation enumeration
+	 */
+	@org.junit.Test
+	public void interpolation() {
+		assertTrue(Interpolation.LINEAR.isLinear());
+		assertFalse(Interpolation.NONE.isSpecific());
+		assertEquals(Interpolation.NONE.ordinal(), (Integer) 0);
+		assertEquals(Interpolation.LINEAR.ordinal(), (Integer) 1);
+		assertEquals(Interpolation.SPECIFIC.ordinal(), (Integer) 2);
+	}
+
+	@org.junit.Test
+	public void enumRegistry() {
+		EnumRegistry er = EnumRegistry.getInstance();
+		assertTrue(er.get("Interpolation") != null);
+	}
+
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ValueTypeTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ValueTypeTest.java
new file mode 100644
index 0000000..fa2914e
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/model/ValueTypeTest.java
@@ -0,0 +1,79 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.model;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.junit.Before;
+
+public class ValueTypeTest {
+
+	@Before
+	public void init() {
+		EnumRegistry.getInstance();
+	}
+
+	@org.junit.Test
+	public void testExtractStringFromUnknown() {
+		Value v = ValueType.UNKNOWN.create("Name", "abcd");
+
+		assertThat((String) v.extract()).isEqualTo("abcd");
+		assertThat(v.extract(ValueType.UNKNOWN)).isEqualTo("abcd");
+	}
+
+	@org.junit.Test
+	public void testExtractString() {
+		Value v = ValueType.STRING.create("Name", "abcd");
+
+		assertThat((String) v.extract()).isEqualTo("abcd");
+		assertThat(v.extract(ValueType.STRING)).isEqualTo("abcd");
+	}
+
+	@org.junit.Test
+	public void testExtractInteger() {
+		Value v = ValueType.INTEGER.create("Id", 1);
+
+		assertThat((int) v.extract()).isEqualTo(1);
+		assertThat(v.extract(ValueType.INTEGER)).isEqualTo(1);
+	}
+
+	@org.junit.Test
+	public void testExtractIntegerSequence() {
+		int[] ints = new int[] { 1, 2, 3 };
+
+		Value v = ValueType.INTEGER_SEQUENCE.create("Ids", ints);
+
+		assertThat((int[]) v.extract()).isEqualTo(ints);
+		assertThat(v.extract(ValueType.INTEGER_SEQUENCE)).isEqualTo(ints);
+	}
+
+	@org.junit.Test
+	public void testExtractEnumeration() {
+		Value v = ValueType.ENUMERATION.create("ScalarTypeField", "", true, ScalarType.INTEGER,
+				EnumRegistry.SCALAR_TYPE);
+
+		assertThat(v.extract(ValueType.ENUMERATION)).isEqualTo(ScalarType.INTEGER);
+	}
+
+	@org.junit.Test
+	public void testExtractEnumerationSequence() {
+		ScalarType[] scalaTypes = new ScalarType[] { ScalarType.FLOAT, ScalarType.INTEGER };
+
+		Value v = ValueType.ENUMERATION_SEQUENCE.create("ScalarTypeSeqField", "", true, scalaTypes,
+				EnumRegistry.SCALAR_TYPE);
+
+		assertThat(v.extract(ValueType.ENUMERATION_SEQUENCE)).isEqualTo(scalaTypes);
+	}
+}
diff --git a/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/query/FilterTest.java b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/query/FilterTest.java
new file mode 100755
index 0000000..87b669d
--- /dev/null
+++ b/org.eclipse.mdm.api.base/src/test/java/org/eclipse/mdm/api/base/query/FilterTest.java
@@ -0,0 +1,113 @@
+/********************************************************************************
+ * Copyright (c) 2015-2019 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v. 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+
+package org.eclipse.mdm.api.base.query;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.eclipse.mdm.api.base.EntityTypeImpl;
+import org.eclipse.mdm.api.base.RelationImpl;
+import org.eclipse.mdm.api.base.RelationImpl.AttributeType;
+import org.eclipse.mdm.api.base.model.EnumRegistry;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test the Filter class
+ * 
+ * @author Alexander Nehmer
+ *
+ */
+public class FilterTest {
+
+	static String[] values = new String[] { "1", "2", "3" };
+
+	@Before
+	public void init() {
+		EnumRegistry.getInstance();
+	}
+
+	/**
+	 * Tests ids(EntityType entityType, Collection<String> ids)
+	 */
+	@Test
+	public void testIdsEntityType() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().ids(new EntityTypeImpl(), Arrays.asList(values));
+
+		String[] filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		Iterator<String> valuesIterator = Arrays.asList(values).iterator();
+		Iterator<String> filterConditionIterator = Arrays.stream(filterCondition).iterator();
+
+		while (valuesIterator.hasNext() && filterConditionIterator.hasNext()) {
+			assertEquals(valuesIterator.next(), filterConditionIterator.next());
+		}
+	}
+
+	/**
+	 * Tests ids(Relation relation, Collection<String> ids)
+	 */
+	@Test
+	public void testIdsRelation() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().ids(new RelationImpl(AttributeType.ID), Arrays.asList(values));
+
+		String[] filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		Iterator<String> valuesIterator = Arrays.asList(values).iterator();
+		Iterator<String> filterConditionIterator = Arrays.stream(filterCondition).iterator();
+
+		while (valuesIterator.hasNext() && filterConditionIterator.hasNext()) {
+			assertEquals(valuesIterator.next(), filterConditionIterator.next());
+		}
+	}
+
+	/**
+	 * Tests id(EntityType entityType, String id)
+	 */
+	@Test
+	public void testIdEntity() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().id(new EntityTypeImpl(), "1");
+
+		String filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		assertEquals(filterCondition, "1");
+	}
+
+	/**
+	 * Tests id(Relation relation, String id)
+	 */
+	@Test
+	public void testIdRelation() {
+		Filter filter = Filter.and();
+		assertEquals(filter.stream().toArray().length, 0);
+
+		filter = Filter.and().id(new RelationImpl(AttributeType.ID), "1");
+
+		String filterCondition = filter.iterator().next().getCondition().getValue().extract();
+
+		assertEquals(filterCondition, "1");
+	}
+}