5.8 DataTypes
5.8.1 DataType Model
The DataType Model is used to define simple and structured data types. Data types are used to describe the structure of the Value Attribute of Variables and their VariableTypes. Therefore each Variable and VariableType is pointing with its DataType Attribute to a Node of the DataType NodeClass as shown in Figure 17.

In many cases, the NodeId of the DataType Node – the DataTypeId – will be well-known to Clients and Servers. Clause 8 defines DataTypes and OPC 10000-6 defines their DataTypeIds. In addition, other organizations may define DataTypes that are well-known in the industry. Well-known DataTypeIds provide for commonality across OPC UA Servers and allow Clients to interpret values without having to read the type description from the Server. Therefore, Servers may use well-known DataTypeIds without representing the corresponding DataType Nodes in their AddressSpaces.
In other cases, DataTypes and their corresponding DataTypeIds may be vendor-defined. Servers should attempt to expose the DataType Nodes and the information about the structure of those DataTypes for Clients to read, although this information might not always be available to the Server.
Figure 18 illustrates the Nodes used in the AddressSpace to describe the structure of a DataType. The DataType points to an Object of type DataTypeEncodingType. Each DataType can have several DataTypeEncoding, for example “Default”, “UA Binary” and “XML” encoding. Services in OPC 10000-4 allow Clients to request an encoding or choosing the “Default” encoding. Each DataTypeEncoding is used by exactly one DataType, that is, it is not permitted for two DataTypes to point to the same DataTypeEncoding.

Since the NodeId of the DataTypeEncoding will be used in some Mappings to identify the DataType and it’s encoding as defined in OPC 10000-6, those NodeIds may also be well-known for well-known DataTypeIds.
5.8.2 Encoding Rules for different kinds of DataTypes
Different kinds of DataTypes are handled differently regarding their encoding and according to whether this encoding is represented in the AddressSpace.
Built-in DataTypes are a fixed set of DataTypes (see OPC 10000-6 for a complete list of Built-in DataTypes). They have no encodings visible in the AddressSpace since the encoding should be known to all OPC UA products. Examples of Built-in DataTypes are Int32 (see 8.26) and Double (see 8.12).
Simple DataTypes are subtypes of the Built-in DataTypes, which are handled on the wire like the Built-in DataType, i.e. they cannot be distinguished on the wire from their Built-in supertypes. Since they are handled like Built-in DataTypes regarding the encoding they cannot have encodings defined in the AddressSpace. Clients can read the DataType Attribute of a Variable or VariableType to identify the Simple DataType of the Value Attribute. An example of a Simple DataType is Duration. It is handled on the wire as a Double but the Client can read the DataType Attribute and thus interpret the value as defined by Duration (see 8.13).
Structured DataTypes are DataTypes that represent structured data and are not defined as Built-in DataTypes. Structured DataTypes inherit directly or indirectly from the DataType Structure defined in 8.32. Structured DataTypes may have several encodings and the encodings are exposed in the AddressSpace. How the encoding of Structured DataTypes is handled on the wire is defined in OPC 10000-6. The encoding of the Structured DataType is transmitted with each value, thus Clients are aware of the DataType without reading the DataType Attribute. The encoding has to be transmitted so the Client is able to interpret the data. An example of a Structured DataType is Argument (see 8.6).
Enumeration DataTypes are DataTypes that represent discrete sets of named values. Enumerations are always encoded as Int32 on the wire as defined in OPC 10000-6. Enumeration DataTypes inherit directly or indirectly from the DataType Enumeration defined in 8.14. Enumerations have no encodings exposed in the AddressSpace. To expose the human-readable representation of an enumerated value the DataType Node may have the EnumStrings Property that contains an array of LocalizedText. The Integer representation of the enumeration value points to a position within that array. EnumValues Property can be used instead of the EnumStrings to support integer representation of enumerations that are not zero-based or have gaps. It contains an array of a Structured DataType containing the integer representation as well as the human-readable representation. An example of an enumeration DataType containing a sparse list of Integers is NodeClass which is defined in 8.29.
An OptionSet can be defined in one of two ways. An OptionSet which is 64 bits or less may be defined as an UInteger DataType and always encoded on the wire as defined in OPC 10000-6. An OptionSet may be defined as an OptionSet DataType which is defined in 8.40 and is encoded on the wire as a Structured DataType. To expose the human-readable representation of an OptionSet the DataType Node shall have the OptionSetValues Property that contains an array of LocalizedText.
In addition to the DataTypes described above, abstract DataTypes are also supported, which do not have any encodings and cannot be exchanged on the wire. Variables and VariableTypes use abstract DataTypes to indicate that their Value may be any one of the subtypes of the abstract DataType. An example of an abstract DataType is Integer which is defined in 8.24.
OPC 10000-6 defines a number of DataEncodings which specify how to serialize DataTypes. Some of these DataEncodings are text based and make use of Name portion the DataType BrowseName. For this reason, the BrowseName for all DataTypes should be Strings that start with a letter and contain only letters, digits or the underscore (_). If a DataType has a BrowseName that does not meet these requirements it will be transformed using the Name encoding rules defined in OPC 10000-6 into a String that meets the requirements. This will result in text based DataEncodings with Names that are not friendly to human readers.
5.8.3 DataType NodeClass
The DataType NodeClass describes the syntax of a Variable Value. DataTypes are defined using the DataType NodeClass, as specified in Table 16.
| Name | Use | Data Type | Description |
|---|---|---|---|
| Attributes | |||
Base NodeClass Attributes | M | -- | Inherited from the Base NodeClass. See 5.2. |
IsAbstract | M | Boolean | A boolean Attribute with the following values: TRUE it is an abstract DataType. FALSE it is not an abstract DataType. |
DataTypeDefinition | O | DataTypeDefinition | The DataTypeDefinition Attribute is used to provide the meta data and encoding information for DataTypes. The abstract DataTypeDefinition DataType is defined in 8.47. Structure and Union DataTypes The Attribute shall be mandatory for DataTypes derived from Structure and Union. For such DataTypes, the Attribute shall contain a structure of the DataType StructureDefinition. The StructureDefinition DataType is defined in 8.48. It is a subtype of DataTypeDefinition. Enumeration and OptionSet DataTypes The Attribute shall be mandatory for DataTypes derived from Enumeration, OptionSet and subtypes of UInteger representing an OptionSet. For such DataTypes, the Attribute shall contain a structure of the DataType EnumDefinition. The EnumDefinition DataType is defined in 8.49. It is a subtype of DataTypeDefinition. |
| References | |||
|---|---|---|---|
HasProperty | 0..* | HasProperty References identify the Properties for the DataType. | |
HasSubtype | 0..* | HasSubtype References may be used to span a data type hierarchy. The inverse Reference identifies the parent type of this type. | |
HasEncoding | 0..* | HasEncoding References identify the encodings of the DataType represented as Objects of type DataTypeEncodingType. Only concrete Structured DataTypes may use HasEncoding References. Abstract, Built-in, Enumeration, and Simple DataTypes are not allowed to be the SourceNode of a HasEncoding Reference. Each concrete Structured DataType shall point to at least one DataTypeEncoding Object with the BrowseName “Default Binary” or “Default XML” having the NamespaceIndex 0. The BrowseName of the DataTypeEncoding Objects shall be unique in the context of a DataType, i.e. a DataType shall not point to two DataTypeEncodings having the same BrowseName. | |
| Standard Properties | |||
|---|---|---|---|
NodeVersion | O | String | The NodeVersion Property is used to indicate the version of a Node. The NodeVersion Property is updated each time a Reference is added or deleted to the Node the Property belongs to. Attribute value changes do not cause the NodeVersion to change. Clients may read the NodeVersion Property or subscribe to it to determine when the structure of a Node has changed. Clients shall not use the content for programmatic purposes except for equality comparisons. |
EnumStrings | O | LocalizedText[] | Enumeration DataTypes shall have either an EnumStrings Property or an EnumValues Property. They shall not be applied for other DataTypes. Each entry of the array of LocalizedText in this Property represents the human-readable representation of an enumerated value. The Integer representation of the enumeration value points to a position of the array. |
EnumValues | O | EnumValueType[] | Enumeration DataTypes shall have either an EnumStrings Property or an EnumValues Property. They shall not be applied for other DataTypes. The EnumValues Property shall be used to represent Enumerations with integers that are not zero-based or have gaps (e.g. 1, 2, 4, 8, and 16). Each entry of the array of EnumValueType in this Property represents one enumeration value with its integer notation, human-readable representation and help information. |
OptionSetValues | O | LocalizedText[] | The OptionSetValues Property shall be applied to OptionSet DataTypes and UInteger DataTypes representing bit masks. An OptionSet DataType or UInteger DataType is used to represent a bit mask and the OptionSetValues Property contains the human-readable representation for each bit of the bit mask. The OptionSetValues Property shall provide an array of LocalizedText containing the human-readable representation for each bit. The LocalizedText of undefined bits shall be null. |
OptionSetLength | O | UInt32 | The OptionSetLength Property shall only be applied to subtypes of the OptionSet DataType. It optionally provides the length, in bytes, of the OptionSet. The provided length shall at least provide enough bytes that all bits defined in the OptionSetValues can be managed. For example, if 18 bits are defined by the OptionSetValues, the OptionSetLength shall be at least 3 bytes. |
The DataType NodeClass inherits the base Attributes from the Base NodeClass defined in 5.2. The IsAbstract Attribute specifies if the DataType is abstract or not. Abstract DataTypes can be used in the AddressSpace, i.e. Variables and VariableTypes can point with their DataType Attribute to an abstract DataType. However, concrete values can never be of an abstract DataType and shall always be of a concrete subtype of the abstract DataType.
HasProperty References are used to identify the Properties of a DataType. The Property NodeVersion is used to indicate the version of the DataType. The Property EnumStrings contains human-readable representations of enumeration values and is only applied to Enumeration DataTypes. Instead of the EnumStrings Property an Enumeration DataType can also use the EnumValues Property to represent Enumerations with integer values that are not zero-based or containing gaps. There are no additional Properties defined for DataTypes in this standard. Additional parts of this series of standards may define additional Properties for DataTypes.
HasSubtype References may be used to expose a data type hierarchy in the AddressSpace. The semantic of subtyping is only defined to the point, that a Server may provide instances of the subtype instead of the DataType. Clients should not make any assumptions about any other semantic with that information. For example, it might not be possible to cast a value of one data type to its base data type. Servers need not provide HasSubtype References, even if their DataTypes span a type hierarchy, however it is required that the subtype provides the inverse Reference to its supertype. Some restrictions apply for subtyping enumeration DataTypes as defined in 8.14.
HasEncoding References point from the DataType to its DataTypeEncodings. Each concrete Structured DataType can point to many DataTypeEncodings, but each DataTypeEncoding shall belong to one DataType, that is, it is not permitted for two DataType Nodes to point to the same DataTypeEncoding Object using HasEncoding References. The DataTypeEncoding Node shall provide the inverse HasEncoding Reference to its DataType.
An abstract DataType is not the SourceNode of a HasEncoding Reference. The DataTypeEncoding of an abstract DataType is provided by its concrete subtypes.
DataType Nodes shall not be the SourceNode of other types of References. However, they may be the TargetNode of other References.
5.8.4 DataTypeEncoding and Encoding Information
If a DataType Node is exposed in the AddressSpace, it shall provide its DataTypeEncodings using HasEncoding References. These References shall be bi-directional. Figure 19 provides an example how DataTypes are modelled in the AddressSpace.

The information on how to encode the DataType is provided in the Attribute DataTypeDefinition of the DataType Node. The content of this Attribute shall not be changed once it had been provided to Clients since Clients might persistently cache this information. If the encoding of a DataType needs to be changed conceptually a new DataType needs to be provided, meaning that a new NodeId shall be used for the DataType. Since Clients identify the DataType via the DataTypeEncodings, also the NodeIds for the DataTypeEncodings of the DataType shall be changed, when the encoding changes.
5.8.5 DataTypeRefinement
5.8.5.1 Overview
A DataTypeRefinement refines the usage of a concrete Structured DataType. It can restrict the usage of fields of the Structured DataType and add meta data to fields of the Structured DataType, like providing the EngineeringUnits or EURange.
In order to restrict the usage for each field of a Structured DataType, the following can be defined:
What DataType can be used, including the maximum array length and maximum string length
If an optional field shall become mandatory or shall not be provided
If a certain subtype of the DataType is allowed or not
The general rules for inheritance apply, as defined in 6.3, i.e., the DataType of a field can only be restricted to subtypes of the original DataType, mandatory fields cannot become optional, etc. If a concrete maximum array length or maximum string length has already been defined, it shall not be changed. If a field is defined that does not allow subtypes, this shall not be changed. If a field is defined that does allow subtypes, this can be changed to disallow subtypes.
Any restrictions on the Structured DataType only affect the usage, not the encoding of the DataType. It is still encoded according to the rules of the Structured DataType.
In addition to the restrictions, the DataTypeRefinement also allows meta data for fields to be added to a Structured DataType.
5.8.5.2 DataTypeRefinement Objects
A DataTypeRefinement is represented by an Object of DataTypeRefinementType (see OPC 10000-5) or a subtype. A DataTypeRefinement Object shall always be referenced using a HasDataTypeRefinement Reference (see 7.30) or subtype from exactly one DataType Node representing a Structured DataType that is being refined.
For each field having a refinement, a Variable of BaseDataVariableType or subtype is referenced using a Reference of HasFieldDescription ReferenceType (see 7.25) or a subtype. The BrowseName of the Variable shall use a BrowseName equal to the name of the field. The Namespace of the BrowseName shall be ignored by a Client when performing an equality check with a field name.
A DataTypeRefinement Object shall not reference any Node with a HasFieldDescription or subtype which is not representing a field of the DataType it refines and shall reference at most one Variable for each field with a HasFieldDescription or subtype.
For the restriction of the field, the rules defined in 5.8.5.1 apply. In Table 17, the mapping of the fields in the StructureField of the DataTypeDefinition Attribute to concepts of a Variable is defined.
| StructureField | Variable Concept | Comment |
| Name | String part of BrowseName Attribute | Must match |
| Description | Description Attribute | No requirements |
| DataType | DataType Attribute | Variable must have the same DataType or a subtype |
| ValueRank | ValueRank Attribute | Must match |
| ArrayDimensions | ArrayDimensions Attribute | For each dimension: If 0, Variable is allowed to be non-zero, otherwise they must match |
| MaxStringLength | MaxStringLength Property | If MaxStringLength is 0, Variable is allowed to be non-zero, otherwise must match |
| IsOptional and StructureWithOptionalFields | Reference to Variable either using HasFieldDescription (stays optional) HasFieldDescriptionSetMandatory (becomes mandatory) or IsDisabledOptionalField (optional field not used) | Only allowed if IsOptional is true. Otherwise IsDisabledOptionalField and HasFieldDescriptionSetMandatory are not allowed. |
| IsOptional and StructureWithSubtypedValues or UnionWithSubtypedValues | AccessLevelEx Attribute, bit NoSubDataTypes | Only allowed if IsOptional is true to set the NoSubDataTypes to true. If IsOptional is false, NoSubDataTypes shall be set. |
By using the subtypes HasFieldDescriptionSetMandatory (see 7.26) a field becomes mandatory, and by IsDisabledOptionalField (see 7.27) an optional field shall not be present. In the AccessLevelEx Attribute, the NoSubDataTypes bit can be used to express that a field where subtypes are allowed, no longer allows subtypes.
Depending on the Structured DataType, some limitations on the DataTypeRefinement occur.
If the DataType of a field being refined is BaseDataType, Structure, Number, Integer or UInteger, the DataType of the field can be restricted by using a subtype or SubtypeRestriction (see 5.8.6) on the Variable refining the field. If the StructureType of the DataType being refined is StructureWithSubtypedValues or UnionWithSubtypedValues and IsOptional of the field is set true, the DataType of that field may be restricted by using a subtype or SubtypeRestriction on the Variable refining the field. In all other cases, it is not allowed to use subtypes on the field and therefore restricting the DataType of the field to subtypes is not allowed.
If the DataType of a Variable refining a field is BaseDataType, Structure, Number, Integer or UInteger, then the AccessLevelEx bit NoSubDataTypes of the Variable shall be true. If the DataType of a field being refined is BaseDataType, Structure, Number, Integer or UInteger, then the AccessLevelEx bit NoSubDataTypes of the Variable may be true or false. If the StructureType of a DataType is StructureWithSubtypedValues or UnionWithSubtypedValues, and IsOptional of the field is true, the AccessLevelEx bit NoSubDataTypes may be true or false. In all other cases the AccessLevelEx bit NoSubDataTypes of a Variable refining a field of a Structured DataType shall be false, as it is not allowed to use subtypes based on the Structured DataType being refined.
If the StructureType of a DataType is Structure or StructureWithSubtypedValues, any refinement of a field of the DataType shall not be referenced with IsDisabledOptionalField or HasFieldDescriptionSetMandatory, as there are no optional fields defined for the DataType. If the StructureType is StructureWithOptionalFields, then the IsDisabledOptionalField or HasFieldDescriptionSetMandatory may be used on a field when IsOptional of that field is true. If the StructureType is Union or UnionWithSubtypedValues then the IsDisabledOptionalField may be used on any field and the HasFieldDescriptionSetMandatory shall not be used. In this case, the semantic of IsDisabledOptionalField implies that the DataType of the field shall not be used in the Union using the DataTypeRefinement.
In Figure 20, an example is given. The structure of X:SuperDataType and X:SubDataType is provided in pseudo-code. The Y:Refinement_1 is refining the X:SubDataType and referenced from the DataType with a HasDataTypeRefinement Reference.
The field1 is defined in the DataType as Number, the DataTypeRefinement restricts this to an Int32. As meta data, the EngineeringUnits is defined as Kelvin, therefore the AnalogUnitType is used as VariableType.
The optional field2 is refined to “not used” by referencing the corresponding Variable with IsDisabledOptionalField.
The field3 is defined in the DataType as Number and a one-dimensional array without a size limitation. In the DataTypeRefinement it is refined as an array of Int32 with the maximum length of 5.
The optional field4, added in the subtype X:SubDataType, of String without a maximum length, becomes in the DataTypeRefinement a mandatory field of String with the MaxStringLength of 50.
The field5 is not refined and stays as an Int32.

As fields of Structured DataTypes may use Structured DataTypes, it may be desirable to refine fields of those fields as well. This can be done as shown in Figure 21. In this example, the Y:Refinement_2 provides similar refinements as Y:Refinement_1, but makes the optional field4 “not used”.
The new optional field6, introduced by X:SubSubDataType, uses the X:SubDataType as DataType. The Y:Refinement_2 makes this optional field mandatory, and by letting the X:field6 Variable reference the Y:Refinement_1 with UsesDataTypeRefinement (see 7.24), this DataTypeRefinement is applied to field6.

5.8.5.3 Usage of DataTypeRefinements
Each DataTypeRefinement Object shall be referenced from exactly one DataType Node using HasDataTypeRefinement or a subtype.
DataTypeRefinements are expressed in an OPC UA information model, by using the non-hierarchical Reference UsesDataTypeRefinement (see 7.24) or a subtype. Those References always starts from an instance of a Variable, where the Structured DataType is used. They point to an Object of DataTypeRefinementType or a subtype, which contains the restrictions and meta data of the DataTypeRefinement.
DataTypeRefinements are only allowed to be used on the concrete occurrence of the usage of the Structured DataType, that is on a Variable.
DataTypeRefinements shall not be used from any DataType Node, from any VariableType, or any InstanceDeclaration, only from concrete Variables. This does include Variables describing a DataTypeRefinement, as shown in Figure 21.
Note, that Method Arguments can be further described using Variables referenced with a HasArgumentDescription. If the Method Argument is a Structured DataType, this Variable can be used as SourceNode for the UsesDataTypeRefinement to further refine the Structured DataType.
5.8.5.4 Example of usage of DataTypeRefinements
An example of DataTypeRefinements is given in Figure 22. The X:SuperDataType has two DataTypeRefinements, its subtype has an additional one. Note that the details of the DataTypeRefinements is not shown in the figure. There are two Objects of Z:SuperObjectType, both using DataTypeRefinements.
Z:Object1 has the Property Z:Prop1 and the DataVariables Z:Var1 and Z:Var2, as defined on the X:SuperObjectType. Although all three Variables use the same DataType, the Z:Prop1 is refined by Y:Refinement_4 and Z:Var2 by Y:Refinement_3. Z:Var1 is not further refined.
Z:Object2 has Z:Prop1 and Z:Var1 as defined on the ObjectType, but refines the DataType from Z:Var2 to X:SubDataType and adds another Variable Z:Var3. Like in Z:Object1, the Z:Prop1 is refined by Y:Refinement_4, and both Z:Var2 and Z:Var3 are refined by Y:Refinement_1.

5.8.6 SubtypeRestriction on a DataType
5.8.6.1 Overview
When a Variable or VariableType is defined, the DataType of the Value is defined by the DataType, ValueRank and ArrayDimensions Attributes. In general, it is always allowed for the Value to use a subtype of the DataType unless restricted in the NoSubDataTypes bit of the AccessLevelEx Attribute. In fields of a structure, using subtypes is allowed when IsOptional is set and it is a StructureWithOptionalFields or the DataType is an abstract DataType like the BaseDataType. In many cases where it is allowed to use subtypes, not all possible subtypes are allowed, but the DataType hierarchy does not allow to restrict this by one supertype. For example, when an Int16 and Int32 are allowed, their common supertype Integer would also allow SByte and Int64.
A SubtypeRestriction limits the usage of subtypes to a subset of all subtypes of a DataType. It is represented by an Object of SubtypeRestrictionType defined in OPC 10000-5. A SubtypeRestriction Object is bound to a DataType by a HasDataTypeRefinement Reference from the DataType to the SubtypeRestriction Object. Each SubtypeRestriction Object shall be referenced from exactly one DataType Node using a HasDataTypeRefinement Reference. A SubtypeRestriction Object is referencing Variables with an AllowedSubtype Reference (see 7.29), and thereby restricting that the DataType including ValueRank and ArrayDimensions of the Variable is allowed to be used as subtype. The general rules of inheritance defined in 6.3 apply, i.e., the DataType shall be the same or a subtype of the DataType, the ValueRank can only be changed according to the subtyping rules, etc.
A SubtypeRestriction Object should have at least two AllowedSubtype References to Variables defining different variations of subtypes. Otherwise, a Variable using the SubtypeRestriction should just use the concrete subtype and does not need a SubtypeRestriction.
In Figure 23, an example of a SubtypeRestriction Object is given. The Y:Restriction1 Object is referenced from Number and therefore can be used by any Variable using the Number DataType. It references two Variables, Y:UInt32 with the DataType UInt32, the ValueRank Scalar which does not allow subtypes and X:IntegerArray, of Integer, ValueRank OneDimension that does allow subtypes (which is required since Integer is an abstract DataType). Thereby, any Variable using the SubtypeRestriction is limiting its values to scalar UInt32s or arrays of Integer or any subtypes of Integer.

In the example, Z:SampleVar is using the Y:Restriction1 by referencing it with UsesSubtypeRestriction. This is allowed since the DataType of Z:SampleVar is Number. The DataTypes always have to match exactly. The NoSubDataTypes is set to true, which is required, since Number is abstract, but would also be required for a concrete DataType, since setting it to true is already restricting it to disallow subtypes.
In order to use a SubtypeRestriction, the ValueRank and ArrayDimensions Attribute of the Variable using the SubtypeRestriction shall be compatible to all referenced Variables using AllowedSubtype, i.e., it is required that based on the definitions of the Variable using the SubtypeRestriction a value based on any of the referenced Variables can be used.
A SubtypeRestriction shall only be used on Variables used as instances, never on InstanceDeclarations or VariableTypes.
For Method Arguments, it can be used in combination with the HasArgumentDescription.
5.8.6.2 SubtypeRestriction on fields of Structured DataTypes
Using a SubtypeRestriction, it is possible to restrict the usage of subtypes on fields of a Structured DataType, by combining it with DataTypeRefinements (see 5.8.5). The Variable used to refine the field in a DataTypeRefinement can be the SourceNode of a UsesSubtypeRestriction, thereby limiting the subtypes that can be used in the field.
In Figure 24, an example is given. The X:SuperDataType contains field1 of a scalar Number. The Y:Refinement_3 of X:SuperDataType defines the field1 to either use a scalar UInt32 or Int32 by referencing the Z:Restriction1. No other subtypes of Number are allowed.
