diff --git a/shared/src/main/scala/io/kaitai/struct/ClassCompiler.scala b/shared/src/main/scala/io/kaitai/struct/ClassCompiler.scala
index b36dbcf92..7a01e00aa 100644
--- a/shared/src/main/scala/io/kaitai/struct/ClassCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/ClassCompiler.scala
@@ -47,6 +47,7 @@ class ClassCompiler(
 
     if (!lang.innerDocstrings)
       compileClassDoc(curClass)
+    lang.classAnnotation(curClass)
     lang.classHeader(curClass.name)
     if (lang.innerDocstrings)
       compileClassDoc(curClass)
@@ -92,14 +93,17 @@ class ClassCompiler(
 
     // Attributes declarations and readers
     val allAttrs: List[MemberSpec] =
-      curClass.seq ++
-      curClass.params ++
       List(
         AttrSpec(List(), RootIdentifier, CalcUserType(topClassName, None)),
         AttrSpec(List(), ParentIdentifier, curClass.parentType)
       ) ++
       ExtraAttrs.forClassSpec(curClass, lang)
+    compileIndexedAttrDeclarations(curClass.seq)
+    compileIndexedAttrDeclarations(curClass.params)
     compileAttrDeclarations(allAttrs)
+
+    compileIndexedAttrReaders(curClass.seq)
+    compileIndexedAttrReaders(curClass.params)
     compileAttrReaders(allAttrs)
 
     curClass.toStringExpr.foreach(expr => lang.classToString(expr))
@@ -192,12 +196,7 @@ class ClassCompiler(
     */
   def compileAttrDeclarations(attrs: List[MemberSpec]): Unit = {
     attrs.foreach { (attr) =>
-      val isNullable = if (lang.switchBytesOnlyAsRaw) {
-        attr.isNullableSwitchRaw
-      } else {
-        attr.isNullable
-      }
-      lang.attributeDeclaration(attr.id, attr.dataTypeComposite, isNullable)
+      lang.attributeDeclaration(attr.id, attr.dataTypeComposite, isNullable(attr))
     }
   }
 
@@ -211,12 +210,45 @@ class ClassCompiler(
       // FIXME: Python should have some form of attribute docs too
       if (!attr.doc.isEmpty && !lang.innerDocstrings)
         lang.attributeDoc(attr.id, attr.doc)
-      val isNullable = if (lang.switchBytesOnlyAsRaw) {
-        attr.isNullableSwitchRaw
-      } else {
-        attr.isNullable
-      }
-      lang.attributeReader(attr.id, attr.dataTypeComposite, isNullable)
+      lang.attributeReader(attr.id, attr.dataTypeComposite, isNullable(attr))
+    }
+  }
+
+  /**
+    * Iterates over a given list of attributes and generates attribute
+    * declarations for each of them, additionally annotate each field.
+    *
+    * @param attrs attribute list to traverse
+    */
+  def compileIndexedAttrDeclarations(attrs: List[MemberSpec]): Unit = {
+    attrs.zipWithIndex.foreach { case (attr, index) =>
+      lang.attributeAnnotation(index, attr)
+      lang.attributeDeclaration(attr.id, attr.dataTypeComposite, isNullable(attr))
+    }
+  }
+
+  /**
+    * Iterates over a given list of attributes and generates attribute
+    * readers (AKA getters) for each of them, additionally annotate each
+    * getter.
+    *
+    * @param attrs attribute list to traverse
+    */
+  def compileIndexedAttrReaders(attrs: List[MemberSpec]): Unit = {
+    attrs.zipWithIndex.foreach { case (attr, index) =>
+      // FIXME: Python should have some form of attribute docs too
+      if (!attr.doc.isEmpty && !lang.innerDocstrings)
+        lang.attributeDoc(attr.id, attr.doc)
+      lang.attributeAnnotation(index, attr)
+      lang.attributeReader(attr.id, attr.dataTypeComposite, isNullable(attr))
+    }
+  }
+
+  def isNullable(attr: MemberSpec): Boolean = {
+    if (lang.switchBytesOnlyAsRaw) {
+      attr.isNullableSwitchRaw
+    } else {
+      attr.isNullable
     }
   }
 
@@ -326,6 +358,7 @@ class ClassCompiler(
 
     if (!lang.innerDocstrings)
       compileInstanceDoc(instName, instSpec)
+    lang.instanceAnnotation(instName, instSpec, true)
     lang.instanceHeader(className, instName, dataType, instSpec.isNullable)
     if (lang.innerDocstrings)
       compileInstanceDoc(instName, instSpec)
@@ -354,6 +387,7 @@ class ClassCompiler(
     } else {
       instSpec.isNullable
     }
+    lang.instanceAnnotation(instName, instSpec, false)
     lang.instanceDeclaration(instName, instSpec.dataTypeComposite, isNullable)
   }
 
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala
index 903ef9544..320812c72 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/JavaCompiler.scala
@@ -65,6 +65,21 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
     out.puts
   }
 
+  override def classAnnotation(spec: ClassSpec): Unit = {
+    if (!spec.isTopLevel) return;
+
+    importList.add("io.kaitai.struct.annotations.Generated")
+
+    out.puts("@Generated(")
+    out.inc
+    out.puts(s"""id = "${spec.name.last}",""")
+    out.puts(s"""version = "${KSVersion.current}",""")
+    out.puts(s"""posInfo = ${config.readStoresPos},""")
+    out.puts(s"""autoRead = ${config.autoRead}""")
+    out.dec
+    out.puts(")")
+  }
+
   override def classHeader(name: String): Unit = {
     val staticStr = if (out.indentLevel > 0) {
       "static "
@@ -197,6 +212,32 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
 
   override def readFooter(): Unit = universalFooter
 
+  override def attributeAnnotation(index: Int, attr: MemberSpec): Unit = {
+    attr match {
+      case param: ParamDefSpec => {
+        importList.add("io.kaitai.struct.annotations.Parameter")
+
+        out.puts(s"""@Parameter(index = ${index}, id = "${param.id.humanReadable}")""")
+      }
+      case field: AttrSpec => {
+        field.id match {
+          case NamedIdentifier(name) => {
+            importList.add("io.kaitai.struct.annotations.SeqItem")
+
+            out.puts(s"""@SeqItem(index = ${index}, id = "${name}")""")
+          }
+          case NumberedIdentifier(_) => {
+            importList.add("io.kaitai.struct.annotations.SeqItem")
+
+            out.puts(s"""@SeqItem(index = ${index})""")
+          }
+          case _ =>
+        }
+      }
+      case _ =>
+    }
+  }
+
   override def attributeDeclaration(attrName: Identifier, attrType: DataType, isNullable: Boolean): Unit = {
     out.puts(s"private ${kaitaiType2JavaType(attrType, isNullable)} ${idToStr(attrName)};")
   }
@@ -649,6 +690,12 @@ class JavaCompiler(typeProvider: ClassTypeProvider, config: RuntimeConfig)
 
   //</editor-fold>
 
+  override def instanceAnnotation(instName: InstanceIdentifier, spec: InstanceSpec, getter: Boolean): Unit = {
+    importList.add("io.kaitai.struct.annotations.Instance")
+
+    out.puts(s"""@Instance(id = "${instName.name}")""")
+  }
+
   override def instanceDeclaration(instName: InstanceIdentifier, attrType: DataType, isNullable: Boolean): Unit = {
     out.puts(s"private ${kaitaiType2JavaTypeBoxed(attrType)} ${idToStr(instName)};")
   }
diff --git a/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala b/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala
index bdfb32b51..a5b6689c8 100644
--- a/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala
+++ b/shared/src/main/scala/io/kaitai/struct/languages/components/LanguageCompiler.scala
@@ -84,6 +84,14 @@ abstract class LanguageCompiler(
   def opaqueClassDeclaration(classSpec: ClassSpec): Unit = {}
 
   def classDoc(name: List[String], doc: DocSpec): Unit = {}
+  /**
+   * Generates additional meta-information for attribute, such as annotations in Java
+   * or attributes in C#. That annotations appears between documentation and main body
+   * of class.
+   *
+   * @param spec Specification of type
+   */
+  def classAnnotation(spec: ClassSpec): Unit = {}
   def classHeader(name: List[String]): Unit
   def classFooter(name: List[String]): Unit
   def classForwardDeclaration(name: List[String]): Unit = {}
@@ -114,6 +122,15 @@ abstract class LanguageCompiler(
     */
   def readFooter(): Unit
 
+  /**
+   * Generates additional meta-information for an attribute or type parameter,
+   * such as annotations in Java or attributes in C#.
+   *
+   * @param index Sequential index of `seq` attribute/parameter in type, started from 0.
+   *        Attributes and parameters have independent indexes
+   * @param attr Specification of attribute
+   */
+  def attributeAnnotation(index: Int, attr: MemberSpec): Unit = {}
   def attributeDeclaration(attrName: Identifier, attrType: DataType, isNullable: Boolean): Unit
   def attributeReader(attrName: Identifier, attrType: DataType, isNullable: Boolean): Unit
   def attributeDoc(id: Identifier, doc: DocSpec): Unit = {}
@@ -151,6 +168,15 @@ abstract class LanguageCompiler(
   def popPos(io: String): Unit
   def alignToByte(io: String): Unit
 
+  /**
+   * Generates additional meta-information for instance, such as annotations in Java
+   * or attributes in C#.
+   *
+   * @param instName Name of instance
+   * @param spec Specification of instance
+   * @param getter If `true`, method called for annotate value getter, otherwise for annotate storage variable
+   */
+  def instanceAnnotation(instName: InstanceIdentifier, spec: InstanceSpec, getter: Boolean): Unit = {}
   def instanceDeclHeader(className: List[String]): Unit = {}
   def instanceClear(instName: InstanceIdentifier): Unit = {}
   def instanceSetCalculated(instName: InstanceIdentifier): Unit = {}