You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fory.apache.org by ch...@apache.org on 2025/10/19 18:56:08 UTC

(fory) branch main updated: feat(rust): dynamic rust serializer system (#2778)

This is an automated email from the ASF dual-hosted git repository.

chaokunyang pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fory.git


The following commit(s) were added to refs/heads/main by this push:
     new c1b7d8095 feat(rust): dynamic rust serializer system (#2778)
c1b7d8095 is described below

commit c1b7d80953868eae55af92b2bb6f3276d4cd64bd
Author: Shawn Yang <sh...@gmail.com>
AuthorDate: Mon Oct 20 02:56:05 2025 +0800

    feat(rust): dynamic rust serializer system (#2778)
    
    ## What does this PR do?
    
    This PR rewrite whole rust serializer to provide a much more clean,
    dynamic and flexible serializer system. Main changes inlucde:
    - New Serializer trait inferface: privide new
    `fory_write`/`fory_write_generic`/`fory_read`/`fory_read_with_type_info`
    API,, to allow control nested serialization behaviour
    - Provide `fory_static_type_id` to allow fast compile-time serializer
    dispatch
    - Implement fory collection/map dynamic xlang serialization protocol,
    make it work with trait object and shared/circular reference
    - Removed `is_field` parameter, it inotroduce lots of confusion to users
    - Rewrite whole error processing system, use static method instead, and
    support dump backtrace in https://github.com/apache/fory/issues/2780
    - Add struct field read/write hook, support dump field write/read info
    and support register customized debug hook
    - Refactored the derive macro with better generated code
    - Move `fory_read_compatible` to `StrucSerializer`
    ## Related issues
    
    - Closes #2777
    - Closes #2775
    - Closes #2780
    
    ## Does this PR introduce any user-facing change?
    
    <!--
    If any user-facing interface changes, please [open an
    issue](https://github.com/apache/fory/issues/new/choose) describing the
    need to do so and update the document if necessary.
    
    Delete section if not applicable.
    -->
    
    - [ ] Does this PR introduce any public API change?
    - [ ] Does this PR introduce any binary protocol compatibility change?
    
    ## Benchmark
    
    <!--
    When the PR has an impact on performance (if you don't know whether the
    PR will have an impact on performance, you can submit the PR first, and
    if it will have impact on performance, the code reviewer will explain
    it), be sure to attach a benchmark data here.
    
    Delete section if not applicable.
    -->
---
 AGENTS.md                                          |   5 +
 CONTRIBUTING.md                                    |   4 +-
 docs/guide/DEVELOPMENT.md                          |   2 +
 rust/README.md                                     |   9 +
 rust/fory-core/src/buffer.rs                       |  11 +-
 rust/fory-core/src/error.rs                        | 380 +++++++++++-
 rust/fory-core/src/fory.rs                         |  96 +--
 rust/fory-core/src/lib.rs                          |   5 +-
 rust/fory-core/src/meta/meta_string.rs             |  55 +-
 rust/fory-core/src/meta/type_meta.rs               |  16 +-
 rust/fory-core/src/resolver/context.rs             | 160 ++---
 rust/fory-core/src/resolver/meta_resolver.rs       |   6 +-
 rust/fory-core/src/resolver/metastring_resolver.rs |   8 +-
 rust/fory-core/src/resolver/ref_resolver.rs        |  17 +-
 rust/fory-core/src/resolver/type_resolver.rs       | 570 ++++++++++-------
 rust/fory-core/src/row/row.rs                      |  12 +-
 rust/fory-core/src/serializer/any.rs               | 514 +++++++++++----
 rust/fory-core/src/serializer/arc.rs               | 162 +++--
 rust/fory-core/src/serializer/bool.rs              |  20 +-
 rust/fory-core/src/serializer/box_.rs              |  24 +-
 rust/fory-core/src/serializer/collection.rs        | 251 ++++++--
 rust/fory-core/src/serializer/core.rs              | 276 +++++++++
 rust/fory-core/src/serializer/datetime.rs          |  62 +-
 rust/fory-core/src/serializer/enum_.rs             | 101 ++-
 rust/fory-core/src/serializer/heap.rs              |  23 +-
 rust/fory-core/src/serializer/list.rs              | 100 ++-
 rust/fory-core/src/serializer/map.rs               | 690 ++++++++++++++++-----
 rust/fory-core/src/serializer/mod.rs               | 303 +--------
 rust/fory-core/src/serializer/mutex.rs             |  75 ++-
 rust/fory-core/src/serializer/number.rs            |  28 +-
 rust/fory-core/src/serializer/option.rs            |  97 ++-
 rust/fory-core/src/serializer/primitive_list.rs    |  27 +-
 rust/fory-core/src/serializer/rc.rs                | 160 +++--
 rust/fory-core/src/serializer/refcell.rs           |  79 ++-
 rust/fory-core/src/serializer/set.rs               |  49 +-
 rust/fory-core/src/serializer/skip.rs              |  82 ++-
 rust/fory-core/src/serializer/string.rs            |  32 +-
 rust/fory-core/src/serializer/struct_.rs           | 170 ++++-
 rust/fory-core/src/serializer/trait_object.rs      | 624 ++++++++++---------
 rust/fory-core/src/serializer/util.rs              |  78 +++
 rust/fory-core/src/serializer/weak.rs              | 323 +++++++---
 rust/fory-core/src/types.rs                        |  86 ++-
 rust/fory-derive/src/lib.rs                        |   9 +-
 rust/fory-derive/src/object/derive_enum.rs         |  45 +-
 rust/fory-derive/src/object/read.rs                | 340 ++++++----
 rust/fory-derive/src/object/serializer.rs          | 105 ++--
 rust/fory-derive/src/object/util.rs                | 262 +++++---
 rust/fory-derive/src/object/write.rs               | 167 ++---
 rust/fory/src/lib.rs                               |   4 +-
 rust/tests/tests/compatible/test_container.rs      |   1 +
 rust/tests/tests/compatible/test_struct.rs         |  10 +
 rust/tests/tests/compatible/test_struct_enum.rs    |  29 +-
 rust/tests/tests/mod.rs                            |   2 +
 rust/tests/tests/test_collection.rs                |   3 +-
 rust/tests/tests/test_cross_language.rs            |  21 +-
 rust/tests/tests/test_debug.rs                     | 195 ++++++
 rust/tests/tests/test_ext.rs                       |   8 +-
 rust/tests/tests/test_max_dyn_depth.rs             |  13 +
 rust/tests/tests/test_meta_string.rs               |   4 +
 .../{test_simple_struct.rs => test_one_struct.rs}  |   1 +
 rust/tests/tests/test_simple_struct.rs             | 188 ++++--
 rust/tests/tests/test_trait_object.rs              |  22 +-
 62 files changed, 4963 insertions(+), 2258 deletions(-)

diff --git a/AGENTS.md b/AGENTS.md
index 7e2cd126e..18786ac25 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -123,6 +123,8 @@ go generate ./...
 
 - All cargo commands must be executed within the `rust` directory.
 - All changes to `rust` must pass the clippy check and tests.
+- You must set `RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1` when debuging rust tests to get backtrace.
+- You must not set `FORY_PANIC_ON_ERROR=1` when runing all rust tests to check whether all tests pass, some tests will check Error content, which will fail if error just panic.
 
 ```bash
 # Check code
@@ -143,6 +145,9 @@ cargo test -p fory-tests  --test $test_file $test_method
 # run specific test under subdirectory
 cargo test --test mod $dir$::$test_file::$test_method
 
+# debug specific test under subdirectory and get backtrace
+RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1 ENABLE_FORY_DEBUG_OUTPUT=1 cargo test --test mod $dir$::$test_file::$test_method
+
 # inspect generated code by fory derive macro
 cargo expand --test mod $mod$::$file$ > expanded.rs
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 180cd2646..b89a77ca7 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,9 @@ cargo test
 # run test with specific test file and method
 cargo test -p fory-tests  --test $test_file $test_method
 # run specific test under subdirectory
- cargo test --test mod $dir$::$test_file::$test_method
+cargo test --test mod $dir$::$test_file::$test_method
+# debug specific test under subdirectory and get backtrace
+RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1 cargo test --test mod $dir$::$test_file::$test_method
 ```
 
 ### JavaScript
diff --git a/docs/guide/DEVELOPMENT.md b/docs/guide/DEVELOPMENT.md
index dc08f8a00..921143aaa 100644
--- a/docs/guide/DEVELOPMENT.md
+++ b/docs/guide/DEVELOPMENT.md
@@ -100,6 +100,8 @@ cargo test
 cargo test -p fory-tests  --test $test_file $test_method
 # run specific test under subdirectory
 cargo test --test mod $dir$::$test_file::$test_method
+# debug specific test under subdirectory and get backtrace
+RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1 cargo test --test mod $dir$::$test_file::$test_method
 # inspect generated code by fory derive macro
 cargo expand --test mod $mod$::$file$ > expanded.rs
 ```
diff --git a/rust/README.md b/rust/README.md
index 607c556be..849afd935 100644
--- a/rust/README.md
+++ b/rust/README.md
@@ -920,6 +920,15 @@ let fory = Fory::default().max_dyn_depth(10); // Allow up to 10 levels
 
 Note: Static data types (non-dynamic types) are secure by nature and not subject to depth limits, as their structure is known at compile time.
 
+## ๐Ÿงช Troubleshooting
+
+- **Type registry errors**: An error like `TypeId ... not found in type_info registry` means the type was never registered with the current `Fory` instance. Confirm that every serializable struct or trait implementation calls `fory.register::<T>(type_id)` before serialization and that the same IDs are reused on the deserialize side.
+- **Quick error lookup**: Prefer the static constructors on `fory_core::error::Error` (`Error::type_mismatch`, `Error::invalid_data`, `Error::unknown`, etc.) rather than instantiating variants manually. This keeps diagnostics consistent and makes opt-in panics work.
+- **Panic on error for backtraces**: Toggle `FORY_PANIC_ON_ERROR=1` (or `true`) alongside `RUST_BACKTRACE=1` when running tests or binaries to panic at the exact site an error is constructed. Reset the variable afterwards to avoid aborting user-facing code paths.
+- **Struct field tracing**: Add the `#[fory_debug]` attribute alongside `#[derive(ForyObject)]` to tell the macro to emit hook invocations for that type. Once compiled with debug hooks, call `set_before_write_field_func`, `set_after_write_field_func`, `set_before_read_field_func`, or `set_after_read_field_func` (from `fory-core/src/serializer/struct_.rs`) to plug in custom callbacks, and use `reset_struct_debug_hooks()` when you want the defaults back.
+- **Lightweight logging**: Without custom hooks, enable `ENABLE_FORY_DEBUG_OUTPUT=1` to print field-level read/write events emitted by the default hook functions. This is especially useful when investigating alignment or cursor mismatches.
+- **Test-time hygiene**: Some integration tests expect `FORY_PANIC_ON_ERROR` to remain unset. Export it only for focused debugging sessions, and prefer `cargo test --features tests -p fory-tests --test <case>` when isolating failing scenarios.
+
 ## ๐Ÿ› ๏ธ Development
 
 ### Building
diff --git a/rust/fory-core/src/buffer.rs b/rust/fory-core/src/buffer.rs
index 576937738..d38bf4fcb 100644
--- a/rust/fory-core/src/buffer.rs
+++ b/rust/fory-core/src/buffer.rs
@@ -374,6 +374,11 @@ impl Reader {
         self.cursor += additional;
     }
 
+    #[inline(always)]
+    pub(crate) fn move_back(&mut self, additional: usize) {
+        self.cursor -= additional;
+    }
+
     #[inline(always)]
     pub(crate) fn ptr_at(&self, offset: usize) -> *const u8 {
         unsafe { self.bf.add(offset) }
@@ -395,10 +400,10 @@ impl Reader {
     fn check_bound(&self, n: usize) -> Result<(), Error> {
         // The upper layer guarantees it is non-null
         // if self.bf.is_null() {
-        //     return Err(Error::InvalidData("buffer pointer is null".into()));
+        //     return Err(Error::invalid_data("buffer pointer is null"));
         // }
         if self.cursor + n > self.len {
-            Err(Error::BufferOutOfBound(self.cursor, n, self.len))
+            Err(Error::buffer_out_of_bound(self.cursor, n, self.len))
         } else {
             Ok(())
         }
@@ -673,7 +678,7 @@ impl Reader {
             }
             shift += 7;
             if shift >= 36 {
-                return Err(Error::EncodeError("varuint36small overflow".into()));
+                return Err(Error::encode_error("varuint36small overflow"));
             }
         }
         Ok(result)
diff --git a/rust/fory-core/src/error.rs b/rust/fory-core/src/error.rs
index 291608033..84606e603 100644
--- a/rust/fory-core/src/error.rs
+++ b/rust/fory-core/src/error.rs
@@ -17,54 +17,402 @@
 
 use std::borrow::Cow;
 use std::io;
+use std::sync::OnceLock;
 
 use thiserror::Error;
 
+/// Global flag to check if FORY_PANIC_ON_ERROR environment variable is set.
+static PANIC_ON_ERROR: OnceLock<bool> = OnceLock::new();
+
+/// Check if FORY_PANIC_ON_ERROR environment variable is set.
+#[inline]
+pub fn should_panic_on_error() -> bool {
+    *PANIC_ON_ERROR.get_or_init(|| {
+        std::env::var("FORY_PANIC_ON_ERROR")
+            .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
+            .unwrap_or(false)
+    })
+}
+
+/// Error type for Fory serialization and deserialization operations.
+///
+/// # IMPORTANT: Always Use Static Constructor Functions
+///
+/// **DO NOT** construct error variants directly using the enum syntax.
+/// **ALWAYS** use the provided static constructor functions instead.
+///
+/// ## Why Use Static Functions?
+///
+/// The static constructor functions provide:
+/// - Automatic type conversion via `Into<Cow<'static, str>>`
+/// - Consistent error creation across the codebase
+/// - Better ergonomics (no need for manual `.into()` calls)
+/// - Future-proof API if error construction logic needs to change
+///
+/// ## Examples
+///
+/// ```rust
+/// use fory_core::error::Error;
+///
+/// // โœ… CORRECT: Use static functions
+/// let err = Error::type_error("Expected string type");
+/// let err = Error::invalid_data(format!("Invalid value: {}", 42));
+/// let err = Error::type_mismatch(1, 2);
+///
+/// // โŒ WRONG: Do not construct directly
+/// // let err = Error::TypeError("Expected string type".into());
+/// // let err = Error::InvalidData(format!("Invalid value: {}", 42).into());
+/// ```
+///
+/// ## Available Constructor Functions
+///
+/// - [`Error::type_mismatch`] - For type ID mismatches
+/// - [`Error::buffer_out_of_bound`] - For buffer boundary violations
+/// - [`Error::encode_error`] - For encoding failures
+/// - [`Error::invalid_data`] - For invalid or corrupted data
+/// - [`Error::invalid_ref`] - For invalid reference IDs
+/// - [`Error::unknown_enum`] - For unknown enum variants
+/// - [`Error::type_error`] - For general type errors
+/// - [`Error::encoding_error`] - For encoding format errors
+/// - [`Error::depth_exceed`] - For exceeding maximum nesting depth
+/// - [`Error::unsupported`] - For unsupported operations
+/// - [`Error::not_allowed`] - For disallowed operations
+/// - [`Error::unknown`] - For generic errors
+///
+/// ## Debug Mode: FORY_PANIC_ON_ERROR
+///
+/// For easier debugging, you can set the `FORY_PANIC_ON_ERROR` environment variable to make
+/// the program panic at the exact location where an error is created. This helps identify
+/// the error source with a full stack trace.
+///
+/// ```bash
+/// RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=1 cargo run
+/// # or
+/// RUST_BACKTRACE=1 FORY_PANIC_ON_ERROR=true cargo test
+/// ```
+///
+/// When enabled, any error created via the static constructor functions will panic immediately
+/// with the error message, allowing you to see the exact call stack in your debugger or
+/// panic output. Use `RUST_BACKTRACE=1` together with `FORY_PANIC_ON_ERROR` to get a full
+/// stack trace showing exactly where the error was created.
 #[derive(Error, Debug)]
 #[non_exhaustive]
 pub enum Error {
+    /// Type mismatch between local and remote type IDs.
+    ///
+    /// Do not construct this variant directly; use [`Error::type_mismatch`] instead.
     #[error("Type mismatch: type_a = {0}, type_b = {1}")]
     TypeMismatch(u32, u32),
 
+    /// Buffer boundary violation during read/write operations.
+    ///
+    /// Do not construct this variant directly; use [`Error::buffer_out_of_bound`] instead.
     #[error("Buffer out of bound: {0} + {1} > {2}")]
     BufferOutOfBound(usize, usize, usize),
 
+    /// IO error from underlying operations.
     #[error("IO error: {0}")]
     Io(#[from] io::Error),
 
+    /// Error during data encoding.
+    ///
+    /// Do not construct this variant directly; use [`Error::encode_error`] instead.
     #[error("{0}")]
     EncodeError(Cow<'static, str>),
 
+    /// Invalid or corrupted data encountered.
+    ///
+    /// Do not construct this variant directly; use [`Error::invalid_data`] instead.
     #[error("{0}")]
     InvalidData(Cow<'static, str>),
 
+    /// Invalid reference ID encountered.
+    ///
+    /// Do not construct this variant directly; use [`Error::invalid_ref`] instead.
     #[error("{0}")]
     InvalidRef(Cow<'static, str>),
 
+    /// Unknown enum variant encountered.
+    ///
+    /// Do not construct this variant directly; use [`Error::unknown_enum`] instead.
     #[error("{0}")]
     UnknownEnum(Cow<'static, str>),
 
+    /// General type-related error.
+    ///
+    /// Do not construct this variant directly; use [`Error::type_error`] instead.
     #[error("{0}")]
     TypeError(Cow<'static, str>),
 
+    /// Error in encoding format or conversion.
+    ///
+    /// Do not construct this variant directly; use [`Error::encoding_error`] instead.
     #[error("{0}")]
     EncodingError(Cow<'static, str>),
 
+    /// Maximum nesting depth exceeded.
+    ///
+    /// Do not construct this variant directly; use [`Error::depth_exceed`] instead.
     #[error("{0}")]
     DepthExceed(Cow<'static, str>),
 
+    /// Unsupported operation or feature.
+    ///
+    /// Do not construct this variant directly; use [`Error::unsupported`] instead.
+    #[error("{0}")]
+    Uunsupported(Cow<'static, str>),
+
+    /// Operation not allowed in current context.
+    ///
+    /// Do not construct this variant directly; use [`Error::not_allowed`] instead.
+    #[error("{0}")]
+    NotAllowed(Cow<'static, str>),
+
+    /// Generic unknown error.
+    ///
     /// Do not construct this variant directly; use [`Error::unknown`] instead.
     #[error("{0}")]
     Unknown(Cow<'static, str>),
 }
 
 impl Error {
+    /// Creates a new [`Error::TypeMismatch`] with the given type IDs.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::type_mismatch(1, 2);
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn type_mismatch(type_a: u32, type_b: u32) -> Self {
+        let err = Error::TypeMismatch(type_a, type_b);
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::BufferOutOfBound`] with the given bounds.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::buffer_out_of_bound(10, 20, 25);
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn buffer_out_of_bound(offset: usize, length: usize, capacity: usize) -> Self {
+        let err = Error::BufferOutOfBound(offset, length, capacity);
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::EncodeError`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::encode_error("Failed to encode");
+    /// let err = Error::encode_error(format!("Failed to encode field {}", "name"));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn encode_error<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::EncodeError(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::InvalidData`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::invalid_data("Invalid data format");
+    /// let err = Error::invalid_data(format!("Invalid data at position {}", 42));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn invalid_data<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::InvalidData(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::InvalidRef`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::invalid_ref("Invalid reference");
+    /// let err = Error::invalid_ref(format!("Invalid ref id {}", 123));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn invalid_ref<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::InvalidRef(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::UnknownEnum`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::unknown_enum("Unknown enum variant");
+    /// let err = Error::unknown_enum(format!("Unknown variant {}", 5));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn unknown_enum<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::UnknownEnum(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::TypeError`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::type_error("Type error");
+    /// let err = Error::type_error(format!("Expected type {}", "String"));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn type_error<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::TypeError(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::EncodingError`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::encoding_error("Encoding failed");
+    /// let err = Error::encoding_error(format!("Failed to encode as {}", "UTF-8"));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn encoding_error<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::EncodingError(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::DepthExceed`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::depth_exceed("Max depth exceeded");
+    /// let err = Error::depth_exceed(format!("Depth {} exceeds max {}", 100, 64));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn depth_exceed<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::DepthExceed(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::Uunsupported`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::unsupported("Unsupported operation");
+    /// let err = Error::unsupported(format!("Type {} not supported", "MyType"));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn unsupported<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::Uunsupported(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
+    /// Creates a new [`Error::NotAllowed`] from a string or static message.
+    ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
+    /// # Example
+    /// ```
+    /// use fory_core::error::Error;
+    ///
+    /// let err = Error::not_allowed("Operation not allowed");
+    /// let err = Error::not_allowed(format!("Cannot perform {}", "delete"));
+    /// ```
+    #[inline(always)]
+    #[track_caller]
+    pub fn not_allowed<S: Into<Cow<'static, str>>>(s: S) -> Self {
+        let err = Error::NotAllowed(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
+    }
+
     /// Creates a new [`Error::Unknown`] from a string or static message.
     ///
     /// This function is a convenient way to produce an error message
     /// from a literal, `String`, or any type that can be converted into
     /// a [`Cow<'static, str>`].
     ///
+    /// If `FORY_PANIC_ON_ERROR` environment variable is set, this will panic with the error message.
+    ///
     /// # Example
     /// ```
     /// use fory_core::error::Error;
@@ -73,8 +421,13 @@ impl Error {
     /// let err = Error::unknown(format!("ID:{} not found", 1));
     /// ```
     #[inline(always)]
+    #[track_caller]
     pub fn unknown<S: Into<Cow<'static, str>>>(s: S) -> Self {
-        Error::Unknown(s.into())
+        let err = Error::Unknown(s.into());
+        if should_panic_on_error() {
+            panic!("FORY_PANIC_ON_ERROR: {}", err);
+        }
+        err
     }
 }
 
@@ -130,3 +483,28 @@ macro_rules! bail {
         return Err($crate::error::Error::unknown(format!($fmt, $($arg)*)))
     };
 }
+
+/// Returns early with a [`Error::NotAllowed`].
+///
+/// # Examples
+/// ```
+/// use fory_core::not_allowed;
+/// use fory_core::error::Error;
+///
+/// fn check_operation() -> Result<(), Error> {
+///     not_allowed!("operation not allowed");
+/// }
+///
+/// fn check_operation_with_context(op: &str) -> Result<(), Error> {
+///     not_allowed!("operation {} not allowed", op);
+/// }
+/// ```
+#[macro_export]
+macro_rules! not_allowed {
+    ($err:expr) => {
+        return Err($crate::error::Error::not_allowed($err))
+    };
+    ($fmt:expr, $($arg:tt)*) => {
+        return Err($crate::error::Error::not_allowed(format!($fmt, $($arg)*)))
+    };
+}
diff --git a/rust/fory-core/src/fory.rs b/rust/fory-core/src/fory.rs
index c80b1a2dc..bb1983ee3 100644
--- a/rust/fory-core/src/fory.rs
+++ b/rust/fory-core/src/fory.rs
@@ -20,7 +20,7 @@ use crate::ensure;
 use crate::error::Error;
 use crate::resolver::context::WriteContext;
 use crate::resolver::context::{Pool, ReadContext};
-use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
+use crate::resolver::type_resolver::TypeResolver;
 use crate::serializer::ForyDefault;
 use crate::serializer::{Serializer, StructSerializer};
 use crate::types::config_flags::IS_NULL_FLAG;
@@ -28,11 +28,8 @@ use crate::types::{
     config_flags::{IS_CROSS_LANGUAGE_FLAG, IS_LITTLE_ENDIAN_FLAG},
     Language, MAGIC_NUMBER, SIZE_OF_REF_AND_TYPE,
 };
-use crate::util::get_ext_actual_type_id;
 use std::sync::OnceLock;
 
-static EMPTY_STRING: String = String::new();
-
 /// The main Fory serialization framework instance.
 ///
 /// `Fory` provides high-performance cross-language serialization and deserialization
@@ -135,6 +132,7 @@ impl Fory {
         // Setting share_meta individually is not supported currently
         self.share_meta = compatible;
         self.compatible = compatible;
+        self.type_resolver.set_compatible(compatible);
         self
     }
 
@@ -313,29 +311,25 @@ impl Fory {
             let magic_numer = reader.read_u16()?;
             ensure!(
                 magic_numer == MAGIC_NUMBER,
-                Error::InvalidData(
-                    format!(
-                        "The fory xlang serialization must start with magic number {:X}. \
+                Error::invalid_data(format!(
+                    "The fory xlang serialization must start with magic number {:X}. \
                     Please check whether the serialization is based on the xlang protocol \
                     and the data didn't corrupt.",
-                        MAGIC_NUMBER
-                    )
-                    .into()
-                )
+                    MAGIC_NUMBER
+                ))
             )
         }
         let bitmap = reader.read_u8()?;
         let peer_is_xlang = (bitmap & IS_CROSS_LANGUAGE_FLAG) != 0;
         ensure!(
             self.xlang == peer_is_xlang,
-            Error::InvalidData("header bitmap mismatch at xlang bit".into())
+            Error::invalid_data("header bitmap mismatch at xlang bit")
         );
         let is_little_endian = (bitmap & IS_LITTLE_ENDIAN_FLAG) != 0;
         ensure!(
             is_little_endian,
-            Error::InvalidData(
+            Error::invalid_data(
                 "Big endian is not supported for now, please ensure peer machine is little endian."
-                    .into()
             )
         );
         let is_none = (bitmap & IS_NULL_FLAG) != 0;
@@ -429,7 +423,7 @@ impl Fory {
                 bytes_to_skip = context.load_meta(meta_offset as usize)?;
             }
         }
-        let result = <T as Serializer>::fory_read(context, false);
+        let result = <T as Serializer>::fory_read(context, true, true);
         if bytes_to_skip > 0 {
             context.reader.skip(bytes_to_skip)?;
         }
@@ -504,7 +498,7 @@ impl Fory {
             if context.is_compatible() {
                 context.writer.write_i32(-1);
             };
-            <T as Serializer>::fory_write(record, context, false)?;
+            <T as Serializer>::fory_write(record, context, true, true, false)?;
             if context.is_compatible() && !context.empty() {
                 context.write_meta(meta_start_offset);
             }
@@ -543,16 +537,7 @@ impl Fory {
         &mut self,
         id: u32,
     ) -> Result<(), Error> {
-        let actual_type_id = T::fory_actual_type_id(id, false, self.compatible);
-        let type_info = TypeInfo::new::<T>(
-            &self.type_resolver,
-            actual_type_id,
-            &EMPTY_STRING,
-            &EMPTY_STRING,
-            false,
-        )?;
-        self.type_resolver.register::<T>(&type_info)?;
-        Ok(())
+        self.type_resolver.register_by_id::<T>(id)
     }
 
     /// Registers a struct type with a namespace and type name for cross-language serialization.
@@ -590,16 +575,8 @@ impl Fory {
         namespace: &str,
         type_name: &str,
     ) -> Result<(), Error> {
-        let actual_type_id = T::fory_actual_type_id(0, true, self.compatible);
-        let type_info = TypeInfo::new::<T>(
-            &self.type_resolver,
-            actual_type_id,
-            namespace,
-            type_name,
-            true,
-        )?;
-        self.type_resolver.register::<T>(&type_info)?;
-        Ok(())
+        self.type_resolver
+            .register_by_namespace::<T>(namespace, type_name)
     }
 
     /// Registers a struct type with a type name (using the default namespace).
@@ -666,16 +643,7 @@ impl Fory {
         &mut self,
         id: u32,
     ) -> Result<(), Error> {
-        let actual_type_id = get_ext_actual_type_id(id, false);
-        let type_info = TypeInfo::new_with_empty_fields::<T>(
-            &self.type_resolver,
-            actual_type_id,
-            &EMPTY_STRING,
-            &EMPTY_STRING,
-            false,
-        )?;
-        self.type_resolver.register_serializer::<T>(&type_info)?;
-        Ok(())
+        self.type_resolver.register_serializer_by_id::<T>(id)
     }
 
     /// Registers a custom serializer type with a namespace and type name.
@@ -699,16 +667,8 @@ impl Fory {
         namespace: &str,
         type_name: &str,
     ) -> Result<(), Error> {
-        let actual_type_id = get_ext_actual_type_id(0, true);
-        let type_info = TypeInfo::new_with_empty_fields::<T>(
-            &self.type_resolver,
-            actual_type_id,
-            namespace,
-            type_name,
-            true,
-        )?;
-        self.type_resolver.register_serializer::<T>(&type_info)?;
-        Ok(())
+        self.type_resolver
+            .register_serializer_by_namespace::<T>(namespace, type_name)
     }
 
     /// Registers a custom serializer type with a type name (using the default namespace).
@@ -730,19 +690,21 @@ impl Fory {
     ) -> Result<(), Error> {
         self.register_serializer_by_namespace::<T>("", type_name)
     }
+
+    /// Registers a generic trait object type for serialization.
+    /// This method should be used to register collection types such as `Vec<T>`, `HashMap<K, V>`, etc.
+    /// Don't register concrete struct types with this method. Use `register()` instead.
+    pub fn register_generic_trait<T: 'static + Serializer + ForyDefault>(
+        &mut self,
+    ) -> Result<(), Error> {
+        self.type_resolver.register_generic_trait::<T>()
+    }
 }
 
-pub fn write_data<T: Serializer>(
-    this: &T,
-    context: &mut WriteContext,
-    is_field: bool,
-) -> Result<(), Error> {
-    T::fory_write_data(this, context, is_field)
+pub fn write_data<T: Serializer>(this: &T, context: &mut WriteContext) -> Result<(), Error> {
+    T::fory_write_data(this, context)
 }
 
-pub fn read_data<T: Serializer + ForyDefault>(
-    context: &mut ReadContext,
-    is_field: bool,
-) -> Result<T, Error> {
-    T::fory_read_data(context, is_field)
+pub fn read_data<T: Serializer + ForyDefault>(context: &mut ReadContext) -> Result<T, Error> {
+    T::fory_read_data(context)
 }
diff --git a/rust/fory-core/src/lib.rs b/rust/fory-core/src/lib.rs
index f4f9f5d6f..cbb277898 100644
--- a/rust/fory-core/src/lib.rs
+++ b/rust/fory-core/src/lib.rs
@@ -190,9 +190,10 @@ pub mod util;
 pub use paste;
 
 pub use crate::buffer::{Reader, Writer};
+pub use crate::error::Error;
 pub use crate::fory::Fory;
 pub use crate::resolver::context::{ReadContext, WriteContext};
-pub use crate::resolver::type_resolver::TypeResolver;
+pub use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 pub use crate::serializer::weak::{ArcWeak, RcWeak};
-pub use crate::serializer::{ForyDefault, Serializer};
+pub use crate::serializer::{ForyDefault, Serializer, StructSerializer};
 pub use crate::types::{RefFlag, TypeId};
diff --git a/rust/fory-core/src/meta/meta_string.rs b/rust/fory-core/src/meta/meta_string.rs
index 357849361..9391b94e4 100644
--- a/rust/fory-core/src/meta/meta_string.rs
+++ b/rust/fory-core/src/meta/meta_string.rs
@@ -77,7 +77,7 @@ impl MetaString {
         let mut strip_last_char = false;
         if encoding != Encoding::Utf8 {
             if bytes.is_empty() {
-                return Err(Error::EncodeError("Encoded data cannot be empty".into()));
+                return Err(Error::encode_error("Encoded data cannot be empty"));
             }
             strip_last_char = (bytes[0] & 0x80) != 0;
         }
@@ -142,13 +142,10 @@ impl MetaStringEncoder {
 
         ensure!(
             input.len() < SHORT_MAX_VALUE,
-            Error::EncodeError(
-                format!(
-                    "Meta string is too long, max:{SHORT_MAX_VALUE}, current:{}",
-                    input.len()
-                )
-                .into()
-            )
+            Error::encode_error(format!(
+                "Meta string is too long, max:{SHORT_MAX_VALUE}, current:{}",
+                input.len()
+            ))
         );
 
         if !self.is_latin(input) {
@@ -263,17 +260,14 @@ impl MetaStringEncoder {
         }
         ensure!(
             input.len() < SHORT_MAX_VALUE,
-            Error::EncodeError(
-                format!(
-                    "Meta string is too long, max:{SHORT_MAX_VALUE}, current:{}",
-                    input.len()
-                )
-                .into()
-            )
+            Error::encode_error(format!(
+                "Meta string is too long, max:{SHORT_MAX_VALUE}, current:{}",
+                input.len()
+            ))
         );
         ensure!(
             encoding == Encoding::Utf8 || self.is_latin(input),
-            Error::EncodeError("Non-ASCII characters in meta string are not allowed".into())
+            Error::encode_error("Non-ASCII characters in meta string are not allowed")
         );
 
         if input.is_empty() {
@@ -421,10 +415,9 @@ impl MetaStringEncoder {
                 '_' => Ok(27),
                 '$' => Ok(28),
                 '|' => Ok(29),
-                _ => Err(Error::EncodeError(
-                    format!("Unsupported character for LOWER_UPPER_DIGIT_SPECIAL encoding: {c}",)
-                        .into(),
-                ))?,
+                _ => Err(Error::encode_error(format!(
+                    "Unsupported character for LOWER_UPPER_DIGIT_SPECIAL encoding: {c}",
+                )))?,
             },
             6 => match c {
                 'a'..='z' => Ok(c as u8 - b'a'),
@@ -436,10 +429,9 @@ impl MetaStringEncoder {
                     } else if c == self.special_char2 {
                         Ok(63)
                     } else {
-                        Err(Error::EncodeError(
-                            format!("Invalid character value for LOWER_SPECIAL decoding: {c:?}",)
-                                .into(),
-                        ))?
+                        Err(Error::encode_error(format!(
+                            "Invalid character value for LOWER_SPECIAL decoding: {c:?}",
+                        )))?
                     }
                 }
             },
@@ -547,9 +539,9 @@ impl MetaStringDecoder {
             27 => Ok('_'),
             28 => Ok('$'),
             29 => Ok('|'),
-            _ => Err(Error::EncodeError(
-                format!("Invalid character value for LOWER_SPECIAL decoding: {char_value}",).into(),
-            ))?,
+            _ => Err(Error::encode_error(format!(
+                "Invalid character value for LOWER_SPECIAL decoding: {char_value}",
+            )))?,
         }
     }
 
@@ -560,12 +552,9 @@ impl MetaStringDecoder {
             52..=61 => Ok((b'0' + char_value - 52) as char),
             62 => Ok(self.special_char1),
             63 => Ok(self.special_char2),
-            _ => Err(Error::EncodeError(
-                format!(
-                    "Invalid character value for LOWER_UPPER_DIGIT_SPECIAL decoding: {char_value}",
-                )
-                .into(),
-            ))?,
+            _ => Err(Error::encode_error(format!(
+                "Invalid character value for LOWER_UPPER_DIGIT_SPECIAL decoding: {char_value}",
+            )))?,
         }
     }
 
diff --git a/rust/fory-core/src/meta/type_meta.rs b/rust/fory-core/src/meta/type_meta.rs
index 8e0d3e9e1..a52f94d4a 100644
--- a/rust/fory-core/src/meta/type_meta.rs
+++ b/rust/fory-core/src/meta/type_meta.rs
@@ -86,13 +86,13 @@ impl FieldType {
         match self.type_id {
             x if x == TypeId::LIST as u32 || x == TypeId::SET as u32 => {
                 let generic = self.generics.first().unwrap();
-                generic.to_bytes(writer, true, false)?;
+                generic.to_bytes(writer, true, generic.nullable)?;
             }
             x if x == TypeId::MAP as u32 => {
                 let key_generic = self.generics.first().unwrap();
                 let val_generic = self.generics.get(1).unwrap();
-                key_generic.to_bytes(writer, true, false)?;
-                val_generic.to_bytes(writer, true, false)?;
+                key_generic.to_bytes(writer, true, key_generic.nullable)?;
+                val_generic.to_bytes(writer, true, val_generic.nullable)?;
             }
             _ => {}
         }
@@ -163,9 +163,9 @@ impl FieldInfo {
             0x00 => Ok(Encoding::Utf8),
             0x01 => Ok(Encoding::AllToLowerSpecial),
             0x02 => Ok(Encoding::LowerUpperDigitSpecial),
-            _ => Err(Error::EncodingError(
-                format!("Unsupported encoding of field name in type meta, value:{value}").into(),
-            ))?,
+            _ => Err(Error::encoding_error(format!(
+                "Unsupported encoding of field name in type meta, value:{value}"
+            )))?,
         }
     }
 
@@ -494,10 +494,10 @@ impl TypeMetaLayer {
             if let Some(type_info_current) =
                 type_resolver.get_type_info_by_name(&namespace.original, &type_name.original)
             {
-                Self::assign_field_ids(type_info_current, &mut sorted_field_infos);
+                Self::assign_field_ids(&type_info_current, &mut sorted_field_infos);
             }
         } else if let Some(type_info_current) = type_resolver.get_type_info_by_id(type_id) {
-            Self::assign_field_ids(type_info_current, &mut sorted_field_infos);
+            Self::assign_field_ids(&type_info_current, &mut sorted_field_infos);
         }
         // if no type found, keep all fields id as -1 to be skipped.
         Ok(TypeMetaLayer::new(
diff --git a/rust/fory-core/src/resolver/context.rs b/rust/fory-core/src/resolver/context.rs
index 94aaa45b3..714f7dda8 100644
--- a/rust/fory-core/src/resolver/context.rs
+++ b/rust/fory-core/src/resolver/context.rs
@@ -25,7 +25,8 @@ use crate::resolver::metastring_resolver::{
     MetaStringBytes, MetaStringReaderResolver, MetaStringWriterResolver,
 };
 use crate::resolver::ref_resolver::{RefReader, RefWriter};
-use crate::resolver::type_resolver::{Harness, TypeResolver};
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
+use crate::types;
 use std::sync::{Arc, Mutex};
 
 pub struct WriteContext {
@@ -85,6 +86,11 @@ impl WriteContext {
         &self.type_resolver
     }
 
+    #[inline(always)]
+    pub fn get_type_info(&self, type_id: &std::any::TypeId) -> Result<Arc<TypeInfo>, Error> {
+        self.type_resolver.get_type_info(type_id)
+    }
+
     /// Check if compatible mode is enabled
     #[inline(always)]
     pub fn is_compatible(&self) -> bool {
@@ -130,52 +136,46 @@ impl WriteContext {
 
     pub fn write_any_typeinfo(
         &mut self,
+        fory_type_id: u32,
         concrete_type_id: std::any::TypeId,
-    ) -> Result<Arc<Harness>, Error> {
-        use crate::types::TypeId as ForyTypeId;
-
-        let type_info = self.type_resolver.get_type_info(concrete_type_id)?;
+    ) -> Result<Arc<TypeInfo>, Error> {
+        if types::is_internal_type(fory_type_id) {
+            self.writer.write_varuint32(fory_type_id);
+            return self
+                .type_resolver
+                .get_type_info_by_id(fory_type_id)
+                .ok_or_else(|| Error::type_error("Type info for internal type not found"));
+        }
+        let type_info = self.type_resolver.get_type_info(&concrete_type_id)?;
         let fory_type_id = type_info.get_type_id();
-
-        // Clone out the data we need from `type_info` to break the borrow
-        let namespace = type_info.get_namespace().clone();
-        let type_name = type_info.get_type_name().clone();
-        let registered_by_name = type_info.is_registered_by_name();
-
-        if registered_by_name {
-            if fory_type_id & 0xff == ForyTypeId::NAMED_STRUCT as u32 {
-                self.writer.write_varuint32(fory_type_id);
+        let namespace = type_info.get_namespace();
+        let type_name = type_info.get_type_name();
+        self.writer.write_varuint32(fory_type_id);
+        // should be compiled to jump table generation
+        match fory_type_id & 0xff {
+            types::NAMED_COMPATIBLE_STRUCT | types::COMPATIBLE_STRUCT => {
+                let meta_index =
+                    self.meta_resolver
+                        .push(concrete_type_id, &self.type_resolver)? as u32;
+                self.writer.write_varuint32(meta_index);
+            }
+            types::NAMED_ENUM | types::NAMED_EXT | types::NAMED_STRUCT => {
                 if self.is_share_meta() {
-                    let meta_index = self.push_meta(concrete_type_id)? as u32;
+                    let meta_index = self
+                        .meta_resolver
+                        .push(concrete_type_id, &self.type_resolver)?
+                        as u32;
                     self.writer.write_varuint32(meta_index);
                 } else {
                     namespace.write_to(&mut self.writer);
                     type_name.write_to(&mut self.writer);
                 }
-            } else if fory_type_id & 0xff == ForyTypeId::NAMED_COMPATIBLE_STRUCT as u32 {
-                self.writer.write_varuint32(fory_type_id);
-                let meta_index = self.push_meta(concrete_type_id)? as u32;
-                self.writer.write_varuint32(meta_index);
-            } else {
-                self.writer.write_varuint32(u32::MAX);
-                namespace.write_to(&mut self.writer);
-                type_name.write_to(&mut self.writer);
             }
-            self.type_resolver
-                .get_name_harness(&namespace, &type_name)
-                .ok_or_else(|| Error::TypeError("Name harness not found".into()))
-        } else {
-            if fory_type_id & 0xff == ForyTypeId::COMPATIBLE_STRUCT as u32 {
-                self.writer.write_varuint32(fory_type_id);
-                let meta_index = self.push_meta(concrete_type_id)? as u32;
-                self.writer.write_varuint32(meta_index);
-            } else {
-                self.writer.write_varuint32(fory_type_id);
+            _ => {
+                // default case: do nothing
             }
-            self.type_resolver
-                .get_harness(fory_type_id)
-                .ok_or_else(|| Error::TypeError("ID harness not found".into()))
         }
+        Ok(type_info)
     }
 
     #[inline(always)]
@@ -284,8 +284,10 @@ impl ReadContext {
     }
 
     #[inline(always)]
-    pub fn get_meta(&self, type_index: usize) -> &Arc<TypeMeta> {
-        self.meta_resolver.get(type_index)
+    pub fn get_meta(&self, type_index: usize) -> Result<&Arc<TypeMeta>, Error> {
+        self.meta_resolver.get(type_index).ok_or_else(|| {
+            Error::type_error(format!("Meta not found for type index: {}", type_index))
+        })
     }
 
     #[inline(always)]
@@ -296,45 +298,48 @@ impl ReadContext {
         )
     }
 
-    pub fn read_any_typeinfo(&mut self) -> Result<Arc<Harness>, Error> {
-        use crate::types::TypeId as ForyTypeId;
-
+    pub fn read_any_typeinfo(&mut self) -> Result<Arc<TypeInfo>, Error> {
         let fory_type_id = self.reader.read_varuint32()?;
-
-        if fory_type_id == u32::MAX {
-            let namespace = self.meta_resolver.read_metastring(&mut self.reader)?;
-            let type_name = self.meta_resolver.read_metastring(&mut self.reader)?;
-            self.type_resolver
-                .get_name_harness(&namespace, &type_name)
-                .ok_or_else(|| Error::TypeError("Name harness not found".into()))
-        } else if fory_type_id & 0xff == ForyTypeId::NAMED_STRUCT as u32 {
-            if self.is_share_meta() {
-                let _meta_index = self.reader.read_varuint32();
-            } else {
-                let namespace = self.meta_resolver.read_metastring(&mut self.reader)?;
-                let type_name = self.meta_resolver.read_metastring(&mut self.reader)?;
-                return self
+        // should be compiled to jump table generation
+        match fory_type_id & 0xff {
+            types::NAMED_COMPATIBLE_STRUCT | types::COMPATIBLE_STRUCT => {
+                let meta_index = self.reader.read_varuint32()? as usize;
+                let remote_meta = self.get_meta(meta_index)?.clone();
+                let local_type_info = self
                     .type_resolver
-                    .get_name_harness(&namespace, &type_name)
-                    .ok_or_else(|| Error::TypeError("Name harness not found".into()));
+                    .get_type_info_by_id(fory_type_id)
+                    .ok_or_else(|| Error::type_error("ID harness not found"))?;
+                // Create a new TypeInfo with remote metadata but local harness
+                // TODO: make self.get_meta return type info
+                Ok(Arc::new(local_type_info.with_remote_meta(remote_meta)))
+            }
+            types::NAMED_ENUM | types::NAMED_EXT | types::NAMED_STRUCT => {
+                if self.is_share_meta() {
+                    let meta_index = self.reader.read_varuint32()? as usize;
+                    self.get_meta(meta_index)?;
+                    self.type_resolver
+                        .get_type_info_by_id(fory_type_id)
+                        .ok_or_else(|| Error::type_error("ID harness not found"))
+                } else {
+                    let namespace = self.meta_resolver.read_metastring(&mut self.reader)?;
+                    let type_name = self.meta_resolver.read_metastring(&mut self.reader)?;
+                    self.type_resolver
+                        .get_type_info_by_msname(&namespace, &type_name)
+                        .ok_or_else(|| Error::type_error("Name harness not found"))
+                }
             }
-            self.type_resolver
-                .get_harness(fory_type_id)
-                .ok_or_else(|| Error::TypeError("ID harness not found".into()))
-        } else if fory_type_id & 0xff == ForyTypeId::NAMED_COMPATIBLE_STRUCT as u32
-            || fory_type_id & 0xff == ForyTypeId::COMPATIBLE_STRUCT as u32
-        {
-            let _meta_index = self.reader.read_varuint32();
-            self.type_resolver
-                .get_harness(fory_type_id)
-                .ok_or_else(|| Error::TypeError("ID harness not found".into()))
-        } else {
-            self.type_resolver
-                .get_harness(fory_type_id)
-                .ok_or_else(|| Error::TypeError("ID harness not found".into()))
+            _ => self
+                .type_resolver
+                .get_type_info_by_id(fory_type_id)
+                .ok_or_else(|| Error::type_error("ID harness not found")),
         }
     }
 
+    #[inline(always)]
+    pub fn get_type_info(&self, type_id: &std::any::TypeId) -> Result<Arc<TypeInfo>, Error> {
+        self.type_resolver.get_type_info(type_id)
+    }
+
     pub fn read_meta_string_bytes(&mut self) -> Result<MetaStringBytes, Error> {
         self.meta_string_resolver
             .read_meta_string_bytes(&mut self.reader)
@@ -344,16 +349,13 @@ impl ReadContext {
     pub fn inc_depth(&mut self) -> Result<(), Error> {
         self.current_depth += 1;
         if self.current_depth > self.max_dyn_depth() {
-            return Err(Error::DepthExceed(
-                format!(
-                    "Maximum dynamic object nesting depth ({}) exceeded. Current depth: {}. \
+            return Err(Error::depth_exceed(format!(
+                "Maximum dynamic object nesting depth ({}) exceeded. Current depth: {}. \
                     This may indicate a circular reference or overly deep object graph. \
                     Consider increasing max_dyn_depth if this is expected.",
-                    self.max_dyn_depth(),
-                    self.current_depth
-                )
-                .into(),
-            ));
+                self.max_dyn_depth(),
+                self.current_depth
+            )));
         }
         Ok(())
     }
diff --git a/rust/fory-core/src/resolver/meta_resolver.rs b/rust/fory-core/src/resolver/meta_resolver.rs
index 2e1e09bab..4cb8b4d90 100644
--- a/rust/fory-core/src/resolver/meta_resolver.rs
+++ b/rust/fory-core/src/resolver/meta_resolver.rs
@@ -41,7 +41,7 @@ impl MetaWriterResolver {
             None => {
                 let index = self.type_defs.len();
                 self.type_defs
-                    .push(type_resolver.get_type_info(type_id)?.get_type_def());
+                    .push(type_resolver.get_type_info(&type_id)?.get_type_def());
                 self.type_id_index_map.insert(type_id, index);
                 Ok(index)
             }
@@ -73,8 +73,8 @@ pub struct MetaReaderResolver {
 }
 
 impl MetaReaderResolver {
-    pub fn get(&self, index: usize) -> &Arc<TypeMeta> {
-        unsafe { self.reading_type_defs.get_unchecked(index) }
+    pub fn get(&self, index: usize) -> Option<&Arc<TypeMeta>> {
+        self.reading_type_defs.get(index)
     }
 
     pub fn load(
diff --git a/rust/fory-core/src/resolver/metastring_resolver.rs b/rust/fory-core/src/resolver/metastring_resolver.rs
index ddc206927..beb6f4445 100644
--- a/rust/fory-core/src/resolver/metastring_resolver.rs
+++ b/rust/fory-core/src/resolver/metastring_resolver.rs
@@ -98,12 +98,12 @@ impl MetaStringBytes {
         }
 
         let first8: [u8; 8] = bytes[0..8].try_into().map_err(|_| {
-            Error::InvalidData(format!("expected at least 8 bytes, got {}", bytes.len()).into())
+            Error::invalid_data(format!("expected at least 8 bytes, got {}", bytes.len()))
         })?;
         let first8 = u64::from_le_bytes(first8);
 
         let second8: [u8; 8] = bytes[8..16].try_into().map_err(|_| {
-            Error::InvalidData(format!("expected at least 16 bytes, got {}", bytes.len()).into())
+            Error::invalid_data(format!("expected at least 16 bytes, got {}", bytes.len()))
         })?;
         let second8 = u64::from_le_bytes(second8);
 
@@ -267,7 +267,7 @@ impl MetaStringReaderResolver {
             self.dynamic_read
                 .get(idx)
                 .and_then(|opt| opt.clone())
-                .ok_or_else(|| Error::InvalidData("dynamic id not found".into()))
+                .ok_or_else(|| Error::invalid_data("dynamic id not found"))
         }
     }
 
@@ -293,7 +293,7 @@ impl MetaStringReaderResolver {
             self.dynamic_read
                 .get(idx)
                 .and_then(|opt| opt.clone())
-                .ok_or_else(|| Error::InvalidData("dynamic id not found".into()))
+                .ok_or_else(|| Error::invalid_data("dynamic id not found"))
         }
     }
 
diff --git a/rust/fory-core/src/resolver/ref_resolver.rs b/rust/fory-core/src/resolver/ref_resolver.rs
index 3ea8ad6c0..84eaa4b26 100644
--- a/rust/fory-core/src/resolver/ref_resolver.rs
+++ b/rust/fory-core/src/resolver/ref_resolver.rs
@@ -84,7 +84,7 @@ impl RefWriter {
 
         if let Some(&ref_id) = self.refs.get(&ptr_addr) {
             writer.write_i8(RefFlag::Ref as i8);
-            writer.write_u32(ref_id);
+            writer.write_varuint32(ref_id);
             true
         } else {
             let ref_id = self.next_ref_id;
@@ -116,7 +116,7 @@ impl RefWriter {
         if let Some(&ref_id) = self.refs.get(&ptr_addr) {
             // This object has been seen before, write a reference
             writer.write_i8(RefFlag::Ref as i8);
-            writer.write_u32(ref_id);
+            writer.write_varuint32(ref_id);
             true
         } else {
             // First time seeing this object, register it and return false
@@ -286,9 +286,9 @@ impl RefReader {
     ///
     /// The RefFlag indicating what type of reference this is
     ///
-    /// # Panics
+    /// # Errors
     ///
-    /// Panics if an invalid reference flag value is encountered
+    /// Errors if an invalid reference flag value is encountered
     pub fn read_ref_flag(&self, reader: &mut Reader) -> Result<RefFlag, Error> {
         let flag_value = reader.read_i8()?;
         Ok(match flag_value {
@@ -296,9 +296,10 @@ impl RefReader {
             -2 => RefFlag::Ref,
             -1 => RefFlag::NotNullValue,
             0 => RefFlag::RefValue,
-            _ => Err(Error::InvalidRef(
-                format!("Invalid reference flag: {}", flag_value).into(),
-            ))?,
+            _ => Err(Error::invalid_ref(format!(
+                "Invalid reference flag: {}",
+                flag_value
+            )))?,
         })
     }
 
@@ -312,7 +313,7 @@ impl RefReader {
     ///
     /// The reference ID as a u32
     pub fn read_ref_id(&self, reader: &mut Reader) -> Result<u32, Error> {
-        reader.read_u32()
+        reader.read_varuint32()
     }
 
     /// Execute all pending callbacks to resolve weak pointer references.
diff --git a/rust/fory-core/src/resolver/type_resolver.rs b/rust/fory-core/src/resolver/type_resolver.rs
index 8321efc60..0fdd8fda5 100644
--- a/rust/fory-core/src/resolver/type_resolver.rs
+++ b/rust/fory-core/src/resolver/type_resolver.rs
@@ -22,19 +22,28 @@ use crate::meta::{
     TYPE_NAME_ENCODINGS,
 };
 use crate::serializer::{ForyDefault, Serializer, StructSerializer};
-use crate::Reader;
+use crate::util::get_ext_actual_type_id;
+use crate::{Reader, TypeId};
+use std::collections::{HashSet, LinkedList};
 use std::sync::Arc;
 use std::{any::Any, collections::HashMap};
 
-type WriteFn = fn(&dyn Any, &mut WriteContext, is_field: bool) -> Result<(), Error>;
+type WriteFn = fn(
+    &dyn Any,
+    &mut WriteContext,
+    write_ref_info: bool,
+    write_type_info: bool,
+    has_enerics: bool,
+) -> Result<(), Error>;
 type ReadFn =
-    fn(&mut ReadContext, is_field: bool, skip_ref_flag: bool) -> Result<Box<dyn Any>, Error>;
+    fn(&mut ReadContext, read_ref_info: bool, read_type_info: bool) -> Result<Box<dyn Any>, Error>;
 
-type WriteDataFn = fn(&dyn Any, &mut WriteContext, is_field: bool) -> Result<(), Error>;
-type ReadDataFn = fn(&mut ReadContext, is_field: bool) -> Result<Box<dyn Any>, Error>;
+type WriteDataFn = fn(&dyn Any, &mut WriteContext, has_generics: bool) -> Result<(), Error>;
+type ReadDataFn = fn(&mut ReadContext) -> Result<Box<dyn Any>, Error>;
 type ToSerializerFn = fn(Box<dyn Any>) -> Result<Box<dyn Serializer>, Error>;
+static EMPTY_STRING: String = String::new();
 
-#[derive(Clone)]
+#[derive(Clone, Debug)]
 pub struct Harness {
     write_fn: WriteFn,
     read_fn: ReadFn,
@@ -89,6 +98,7 @@ pub struct TypeInfo {
     namespace: MetaString,
     type_name: MetaString,
     register_by_name: bool,
+    harness: Harness,
 }
 
 impl TypeInfo {
@@ -98,6 +108,7 @@ impl TypeInfo {
         namespace: &str,
         type_name: &str,
         register_by_name: bool,
+        harness: Harness,
     ) -> Result<TypeInfo, Error> {
         let namespace_metastring =
             NAMESPACE_ENCODER.encode_with_encodings(namespace, NAMESPACE_ENCODINGS)?;
@@ -139,6 +150,7 @@ impl TypeInfo {
             namespace: namespace_metastring,
             type_name: type_name_metastring,
             register_by_name,
+            harness,
         })
     }
 
@@ -148,6 +160,7 @@ impl TypeInfo {
         namespace: &str,
         type_name: &str,
         register_by_name: bool,
+        harness: Harness,
     ) -> Result<TypeInfo, Error> {
         let namespace_metastring =
             NAMESPACE_ENCODER.encode_with_encodings(namespace, NAMESPACE_ENCODINGS)?;
@@ -169,6 +182,7 @@ impl TypeInfo {
             namespace: namespace_metastring,
             type_name: type_name_metastring,
             register_by_name,
+            harness,
         })
     }
 
@@ -195,20 +209,37 @@ impl TypeInfo {
     pub fn is_registered_by_name(&self) -> bool {
         self.register_by_name
     }
+
+    pub fn get_harness(&self) -> &Harness {
+        &self.harness
+    }
+
+    /// Create a new TypeInfo with the same properties but different type_meta.
+    /// This is used during deserialization to create a TypeInfo with remote metadata
+    /// while keeping the local harness for deserialization functions.
+    pub fn with_remote_meta(&self, remote_meta: Arc<TypeMeta>) -> TypeInfo {
+        TypeInfo {
+            type_def: self.type_def.clone(),
+            type_meta: remote_meta,
+            type_id: self.type_id,
+            namespace: self.namespace.clone(),
+            type_name: self.type_name.clone(),
+            register_by_name: self.register_by_name,
+            harness: self.harness.clone(),
+        }
+    }
 }
 
 /// TypeResolver is a resolver for fast type/serializer dispatch.
 #[derive(Clone)]
 pub struct TypeResolver {
-    serializer_map: HashMap<u32, Arc<Harness>>,
-    name_serializer_map: HashMap<(MetaString, MetaString), Arc<Harness>>,
-    type_id_map: HashMap<std::any::TypeId, u32>,
-    type_name_map: HashMap<std::any::TypeId, (MetaString, MetaString)>,
-    type_info_cache: HashMap<std::any::TypeId, TypeInfo>,
-    type_info_map_by_id: HashMap<u32, TypeInfo>,
-    type_info_map_by_name: HashMap<(String, String), TypeInfo>,
+    type_info_map_by_id: HashMap<u32, Arc<TypeInfo>>,
+    type_info_map: HashMap<std::any::TypeId, Arc<TypeInfo>>,
+    type_info_map_by_name: HashMap<(String, String), Arc<TypeInfo>>,
+    type_info_map_by_ms_name: HashMap<(MetaString, MetaString), Arc<TypeInfo>>,
     // Fast lookup by numeric ID for common types
     type_id_index: Vec<u32>,
+    compatible: bool,
 }
 
 const NO_TYPE_ID: u32 = 1000000000;
@@ -216,14 +247,12 @@ const NO_TYPE_ID: u32 = 1000000000;
 impl Default for TypeResolver {
     fn default() -> Self {
         let mut registry = TypeResolver {
-            serializer_map: HashMap::new(),
-            name_serializer_map: HashMap::new(),
-            type_id_map: HashMap::new(),
-            type_name_map: HashMap::new(),
-            type_info_cache: HashMap::new(),
             type_info_map_by_id: HashMap::new(),
+            type_info_map: HashMap::new(),
             type_info_map_by_name: HashMap::new(),
+            type_info_map_by_ms_name: HashMap::new(),
             type_id_index: Vec::new(),
+            compatible: false,
         };
         registry.register_builtin_types().unwrap();
         registry
@@ -231,21 +260,35 @@ impl Default for TypeResolver {
 }
 
 impl TypeResolver {
-    pub fn get_type_info(&self, type_id: std::any::TypeId) -> Result<&TypeInfo, Error> {
-        self.type_info_cache.get(&type_id)
-            .ok_or_else(|| Error::TypeError(format!(
-                "TypeId {:?} not found in type_info registry, maybe you forgot to register some types",
-                type_id
-            ).into()))
+    pub fn get_type_info(&self, type_id: &std::any::TypeId) -> Result<Arc<TypeInfo>, Error> {
+        self.type_info_map.get(type_id)
+                .ok_or_else(|| {
+                    Error::type_error(format!(
+                        "TypeId {:?} not found in type_info registry, maybe you forgot to register some types",
+                        type_id
+                    ))
+                })
+            .cloned()
     }
 
-    pub fn get_type_info_by_id(&self, id: u32) -> Option<&TypeInfo> {
-        self.type_info_map_by_id.get(&id)
+    pub fn get_type_info_by_id(&self, id: u32) -> Option<Arc<TypeInfo>> {
+        self.type_info_map_by_id.get(&id).cloned()
     }
 
-    pub fn get_type_info_by_name(&self, namespace: &str, type_name: &str) -> Option<&TypeInfo> {
+    pub fn get_type_info_by_name(&self, namespace: &str, type_name: &str) -> Option<Arc<TypeInfo>> {
         self.type_info_map_by_name
             .get(&(namespace.to_owned(), type_name.to_owned()))
+            .cloned()
+    }
+
+    pub fn get_type_info_by_msname(
+        &self,
+        namespace: &MetaString,
+        type_name: &MetaString,
+    ) -> Option<Arc<TypeInfo>> {
+        self.type_info_map_by_ms_name
+            .get(&(namespace.clone(), type_name.clone()))
+            .cloned()
     }
 
     /// Fast path for getting type info by numeric ID (avoids HashMap lookup by TypeId)
@@ -257,17 +300,16 @@ impl TypeResolver {
                 return Ok(type_id);
             }
         }
-        Err(Error::TypeError(
-            format!(
-                "TypeId {:?} not found in type_id_index, maybe you forgot to register some types",
-                type_id
-            )
-            .into(),
-        ))
+        Err(Error::type_error(format!(
+            "TypeId {:?} not found in type_id_index, maybe you forgot to register some types",
+            type_id
+        )))
     }
 
     pub fn get_harness(&self, id: u32) -> Option<Arc<Harness>> {
-        self.serializer_map.get(&id).cloned()
+        self.type_info_map_by_id
+            .get(&id)
+            .map(|info| Arc::new(info.get_harness().clone()))
     }
 
     pub fn get_name_harness(
@@ -276,14 +318,16 @@ impl TypeResolver {
         type_name: &MetaString,
     ) -> Option<Arc<Harness>> {
         let key = (namespace.clone(), type_name.clone());
-        self.name_serializer_map.get(&key).cloned()
+        self.type_info_map_by_ms_name
+            .get(&key)
+            .map(|info| Arc::new(info.get_harness().clone()))
     }
 
     pub fn get_ext_harness(&self, id: u32) -> Result<Arc<Harness>, Error> {
-        self.serializer_map
+        self.type_info_map_by_id
             .get(&id)
-            .cloned()
-            .ok_or_else(|| Error::TypeError("ext type must be registered in both peers".into()))
+            .map(|info| Arc::new(info.get_harness().clone()))
+            .ok_or_else(|| Error::type_error("ext type must be registered in both peers"))
     }
 
     pub fn get_ext_name_harness(
@@ -292,118 +336,124 @@ impl TypeResolver {
         type_name: &MetaString,
     ) -> Result<Arc<Harness>, Error> {
         let key = (namespace.clone(), type_name.clone());
-        self.name_serializer_map.get(&key).cloned().ok_or_else(|| {
-            Error::TypeError("named_ext type must be registered in both peers".into())
-        })
+        self.type_info_map_by_ms_name
+            .get(&key)
+            .map(|info| Arc::new(info.get_harness().clone()))
+            .ok_or_else(|| Error::type_error("named_ext type must be registered in both peers"))
     }
 
     pub fn get_fory_type_id(&self, rust_type_id: std::any::TypeId) -> Option<u32> {
-        if let Some(type_info) = self.type_info_cache.get(&rust_type_id) {
-            Some(type_info.get_type_id())
-        } else {
-            self.type_id_map.get(&rust_type_id).copied()
-        }
+        self.type_info_map
+            .get(&rust_type_id)
+            .map(|info| info.get_type_id())
     }
 
     fn register_builtin_types(&mut self) -> Result<(), Error> {
-        use crate::types::TypeId;
-        let namespace = NAMESPACE_ENCODER.encode_with_encodings("", NAMESPACE_ENCODINGS)?;
-        let type_name = TYPE_NAME_ENCODER.encode_with_encodings("", TYPE_NAME_ENCODINGS)?;
-
-        macro_rules! register_basic_type {
-            ($ty:ty, $type_id:expr) => {{
-                let type_info = TypeInfo {
-                    type_def: Arc::from(vec![]),
-                    type_meta: Arc::new(TypeMeta::empty()),
-                    type_id: $type_id as u32,
-                    namespace: namespace.clone(),
-                    type_name: type_name.clone(),
-                    register_by_name: false,
-                };
-                self.register_serializer::<$ty>(&type_info)?;
-            }};
-        }
-
-        register_basic_type!(bool, TypeId::BOOL);
-        register_basic_type!(i8, TypeId::INT8);
-        register_basic_type!(i16, TypeId::INT16);
-        register_basic_type!(i32, TypeId::INT32);
-        register_basic_type!(i64, TypeId::INT64);
-        register_basic_type!(f32, TypeId::FLOAT32);
-        register_basic_type!(f64, TypeId::FLOAT64);
-        register_basic_type!(String, TypeId::STRING);
-
-        register_basic_type!(Vec<bool>, TypeId::BOOL_ARRAY);
-        register_basic_type!(Vec<i8>, TypeId::INT8_ARRAY);
-        register_basic_type!(Vec<i16>, TypeId::INT16_ARRAY);
-        register_basic_type!(Vec<i32>, TypeId::INT32_ARRAY);
-        register_basic_type!(Vec<i64>, TypeId::INT64_ARRAY);
-        register_basic_type!(Vec<f32>, TypeId::FLOAT32_ARRAY);
-        register_basic_type!(Vec<f64>, TypeId::FLOAT64_ARRAY);
+        self.register_internal_serializer::<bool>(TypeId::BOOL)?;
+        self.register_internal_serializer::<i8>(TypeId::INT8)?;
+        self.register_internal_serializer::<i16>(TypeId::INT16)?;
+        self.register_internal_serializer::<i32>(TypeId::INT32)?;
+        self.register_internal_serializer::<i64>(TypeId::INT64)?;
+        self.register_internal_serializer::<f32>(TypeId::FLOAT32)?;
+        self.register_internal_serializer::<f64>(TypeId::FLOAT64)?;
+        self.register_internal_serializer::<String>(TypeId::STRING)?;
+
+        self.register_internal_serializer::<Vec<bool>>(TypeId::BOOL_ARRAY)?;
+        self.register_internal_serializer::<Vec<i8>>(TypeId::INT8_ARRAY)?;
+        self.register_internal_serializer::<Vec<i16>>(TypeId::INT16_ARRAY)?;
+        self.register_internal_serializer::<Vec<i32>>(TypeId::INT32_ARRAY)?;
+        self.register_internal_serializer::<Vec<i64>>(TypeId::INT64_ARRAY)?;
+        self.register_internal_serializer::<Vec<f32>>(TypeId::FLOAT32_ARRAY)?;
+        self.register_internal_serializer::<Vec<f64>>(TypeId::FLOAT64_ARRAY)?;
+        self.register_generic_trait::<Vec<String>>()?;
+        self.register_generic_trait::<LinkedList<i32>>()?;
+        self.register_generic_trait::<LinkedList<String>>()?;
+        self.register_generic_trait::<HashSet<String>>()?;
+        self.register_generic_trait::<HashSet<i32>>()?;
+        self.register_generic_trait::<HashSet<i64>>()?;
+        self.register_generic_trait::<HashMap<String, String>>()?;
+        self.register_generic_trait::<HashMap<String, i32>>()?;
+        self.register_generic_trait::<HashMap<String, i64>>()?;
 
         Ok(())
     }
 
-    pub fn register<T: StructSerializer + Serializer + ForyDefault>(
+    pub fn register_by_id<T: 'static + StructSerializer + Serializer + ForyDefault>(
+        &mut self,
+        id: u32,
+    ) -> Result<(), Error> {
+        self.register::<T>(id, &EMPTY_STRING, &EMPTY_STRING)
+    }
+
+    pub fn register_by_namespace<T: 'static + StructSerializer + Serializer + ForyDefault>(
         &mut self,
-        type_info: &TypeInfo,
+        namespace: &str,
+        type_name: &str,
     ) -> Result<(), Error> {
+        self.register::<T>(0, namespace, type_name)
+    }
+
+    fn register<T: StructSerializer + Serializer + ForyDefault>(
+        &mut self,
+        id: u32,
+        namespace: &str,
+        type_name: &str,
+    ) -> Result<(), Error> {
+        let register_by_name = !type_name.is_empty();
+        if !register_by_name && id == 0 {
+            return Err(Error::not_allowed(
+                "Either id must be non-zero for ID registration, or type_name must be non-empty for name registration",
+            ));
+        }
+        let actual_type_id = T::fory_actual_type_id(id, register_by_name, self.compatible);
+
         fn write<T2: 'static + Serializer>(
             this: &dyn Any,
             context: &mut WriteContext,
-            is_field: bool,
+            write_ref_info: bool,
+            write_type_info: bool,
+            has_generics: bool,
         ) -> Result<(), Error> {
             let this = this.downcast_ref::<T2>();
             match this {
                 Some(v) => {
-                    let skip_ref_flag =
-                        crate::serializer::get_skip_ref_flag::<T2>(context.get_type_resolver())?;
-                    crate::serializer::write_ref_info_data(
-                        v,
-                        context,
-                        is_field,
-                        skip_ref_flag,
-                        true,
-                    )?;
-                    Ok(())
+                    T2::fory_write(v, context, write_ref_info, write_type_info, has_generics)
                 }
-                None => todo!(),
+                None => Err(Error::type_error(format!(
+                    "Cast type error when writing: {:?}",
+                    T2::fory_static_type_id()
+                ))),
             }
         }
 
         fn read<T2: 'static + Serializer + ForyDefault>(
             context: &mut ReadContext,
-            is_field: bool,
-            skip_ref_flag: bool,
+            read_ref_info: bool,
+            read_type_info: bool,
         ) -> Result<Box<dyn Any>, Error> {
-            match crate::serializer::read_ref_info_data::<T2>(
+            Ok(Box::new(T2::fory_read(
                 context,
-                is_field,
-                skip_ref_flag,
-                true,
-            ) {
-                Ok(v) => Ok(Box::new(v)),
-                Err(e) => Err(e),
-            }
+                read_ref_info,
+                read_type_info,
+            )?))
         }
 
         fn write_data<T2: 'static + Serializer>(
             this: &dyn Any,
             context: &mut WriteContext,
-            is_field: bool,
+            has_generics: bool,
         ) -> Result<(), Error> {
             let this = this.downcast_ref::<T2>();
             match this {
-                Some(v) => T2::fory_write_data(v, context, is_field),
+                Some(v) => T2::fory_write_data_generic(v, context, has_generics),
                 None => todo!(),
             }
         }
 
         fn read_data<T2: 'static + Serializer + ForyDefault>(
             context: &mut ReadContext,
-            is_field: bool,
         ) -> Result<Box<dyn Any>, Error> {
-            match T2::fory_read_data(context, is_field) {
+            match T2::fory_read_data(context) {
                 Ok(v) => Ok(Box::new(v)),
                 Err(e) => Err(e),
             }
@@ -414,131 +464,172 @@ impl TypeResolver {
         ) -> Result<Box<dyn Serializer>, Error> {
             match boxed_any.downcast::<T2>() {
                 Ok(concrete) => Ok(Box::new(*concrete) as Box<dyn Serializer>),
-                Err(_) => Err(Error::TypeError(
-                    "Failed to downcast to concrete type".into(),
-                )),
+                Err(_) => Err(Error::type_error("Failed to downcast to concrete type")),
             }
         }
 
+        let harness = Harness::new(
+            write::<T>,
+            read::<T>,
+            write_data::<T>,
+            read_data::<T>,
+            to_serializer::<T>,
+        );
+
+        let type_info = TypeInfo::new::<T>(
+            self,
+            actual_type_id,
+            namespace,
+            type_name,
+            register_by_name,
+            harness,
+        )?;
+
         let rs_type_id = std::any::TypeId::of::<T>();
-        if self.type_info_cache.contains_key(&rs_type_id) {
-            return Err(Error::TypeError(
-                format!("rs_struct:{:?} already registered", rs_type_id).into(),
-            ));
+        if self.type_info_map.contains_key(&rs_type_id) {
+            return Err(Error::type_error(format!(
+                "rs_struct:{:?} already registered",
+                rs_type_id
+            )));
         }
-        self.type_info_cache.insert(rs_type_id, type_info.clone());
+
+        // Store in main map
+        self.type_info_map
+            .insert(rs_type_id, Arc::new(type_info.clone()));
+
+        // Store by ID
         self.type_info_map_by_id
-            .insert(type_info.type_id, type_info.clone());
+            .insert(type_info.type_id, Arc::new(type_info.clone()));
+
+        // Update type_id_index for fast lookup
         let index = T::fory_type_index() as usize;
         if index >= self.type_id_index.len() {
             self.type_id_index.resize(index + 1, NO_TYPE_ID);
         } else if self.type_id_index[index] != NO_TYPE_ID {
-            return Err(Error::TypeError(
-                format!("please:{:?} already registered", type_info.type_id).into(),
-            ));
+            return Err(Error::type_error(format!(
+                "Type index {:?} already registered",
+                index
+            )));
         }
         self.type_id_index[index] = type_info.type_id;
 
+        // Store by name if registered by name
         if type_info.register_by_name {
             let namespace = &type_info.namespace;
             let type_name = &type_info.type_name;
-            let key = (namespace.clone(), type_name.clone());
-            if self.name_serializer_map.contains_key(&key) {
-                return Err(Error::InvalidData(
-                    format!(
-                        "Namespace:{:?} Name:{:?} already registered_by_name",
-                        namespace, type_name
-                    )
-                    .into(),
-                ));
+            let ms_key = (namespace.clone(), type_name.clone());
+            if self.type_info_map_by_ms_name.contains_key(&ms_key) {
+                return Err(Error::invalid_data(format!(
+                    "Namespace:{:?} Name:{:?} already registered_by_name",
+                    namespace, type_name
+                )));
             }
-            self.type_name_map.insert(rs_type_id, key.clone());
-            self.name_serializer_map.insert(
-                key,
-                Arc::from(Harness::new(
-                    write::<T>,
-                    read::<T>,
-                    write_data::<T>,
-                    read_data::<T>,
-                    to_serializer::<T>,
-                )),
-            );
+            self.type_info_map_by_ms_name
+                .insert(ms_key, Arc::new(type_info.clone()));
             let string_key = (namespace.original.clone(), type_name.original.clone());
             self.type_info_map_by_name
-                .insert(string_key, type_info.clone());
-        } else {
-            let type_id = type_info.type_id;
-            if self.serializer_map.contains_key(&type_id) {
-                return Err(Error::TypeError(
-                    format!("TypeId {:?} already registered_by_id", type_id).into(),
-                ));
-            }
-            self.type_id_map.insert(rs_type_id, type_id);
-            self.serializer_map.insert(
-                type_id,
-                Arc::from(Harness::new(
-                    write::<T>,
-                    read::<T>,
-                    write_data::<T>,
-                    read_data::<T>,
-                    to_serializer::<T>,
-                )),
-            );
+                .insert(string_key, Arc::new(type_info));
         }
         Ok(())
     }
 
-    pub fn register_serializer<T: Serializer + ForyDefault>(
+    pub fn register_serializer_by_id<T: Serializer + ForyDefault>(
         &mut self,
-        type_info: &TypeInfo,
+        id: u32,
     ) -> Result<(), Error> {
+        let actual_type_id = get_ext_actual_type_id(id, false);
+        let static_type_id = T::fory_static_type_id();
+        if static_type_id != TypeId::EXT && static_type_id != TypeId::NAMED_EXT {
+            return Err(Error::not_allowed(
+                "register_serializer can only be used for ext and named_ext types",
+            ));
+        }
+        self.register_serializer::<T>(id, actual_type_id, &EMPTY_STRING, &EMPTY_STRING)
+    }
+
+    pub fn register_serializer_by_namespace<T: Serializer + ForyDefault>(
+        &mut self,
+        namespace: &str,
+        type_name: &str,
+    ) -> Result<(), Error> {
+        let actual_type_id = get_ext_actual_type_id(0, true);
+        let static_type_id = T::fory_static_type_id();
+        if static_type_id != TypeId::EXT && static_type_id != TypeId::NAMED_EXT {
+            return Err(Error::not_allowed(
+                "register_serializer can only be used for ext and named_ext types",
+            ));
+        }
+        self.register_serializer::<T>(0, actual_type_id, namespace, type_name)
+    }
+
+    fn register_internal_serializer<T: Serializer + ForyDefault>(
+        &mut self,
+        type_id: TypeId,
+    ) -> Result<(), Error> {
+        self.register_serializer::<T>(type_id as u32, type_id as u32, &EMPTY_STRING, &EMPTY_STRING)
+    }
+
+    fn register_serializer<T: Serializer + ForyDefault>(
+        &mut self,
+        id: u32,
+        actual_type_id: u32,
+        namespace: &str,
+        type_name: &str,
+    ) -> Result<(), Error> {
+        let register_by_name = !type_name.is_empty();
+        if !register_by_name && id == 0 {
+            return Err(Error::not_allowed(
+                "Either id must be non-zero for ID registration, or type_name must be non-empty for name registration",
+            ));
+        }
+
         fn write<T2: 'static + Serializer>(
             this: &dyn Any,
             context: &mut WriteContext,
-            is_field: bool,
+            write_ref_info: bool,
+            write_type_info: bool,
+            has_generics: bool,
         ) -> Result<(), Error> {
             let this = this.downcast_ref::<T2>();
             match this {
-                Some(v) => Ok(v.fory_write(context, is_field)?),
-                None => todo!(),
+                Some(v) => {
+                    Ok(v.fory_write(context, write_ref_info, write_type_info, has_generics)?)
+                }
+                None => Err(Error::type_error(format!(
+                    "Cast type error when writing: {:?}",
+                    T2::fory_static_type_id()
+                ))),
             }
         }
 
         fn read<T2: 'static + Serializer + ForyDefault>(
             context: &mut ReadContext,
-            is_field: bool,
-            skip_ref_flag: bool,
+            read_ref_info: bool,
+            read_type_info: bool,
         ) -> Result<Box<dyn Any>, Error> {
-            if skip_ref_flag {
-                match T2::fory_read_data(context, is_field) {
-                    Ok(v) => Ok(Box::new(v)),
-                    Err(e) => Err(e),
-                }
-            } else {
-                match T2::fory_read(context, is_field) {
-                    Ok(v) => Ok(Box::new(v)),
-                    Err(e) => Err(e),
-                }
-            }
+            Ok(Box::new(T2::fory_read(
+                context,
+                read_ref_info,
+                read_type_info,
+            )?))
         }
 
         fn write_data<T2: 'static + Serializer>(
             this: &dyn Any,
             context: &mut WriteContext,
-            is_field: bool,
+            has_generics: bool,
         ) -> Result<(), Error> {
             let this = this.downcast_ref::<T2>();
             match this {
-                Some(v) => T2::fory_write_data(v, context, is_field),
+                Some(v) => T2::fory_write_data_generic(v, context, has_generics),
                 None => todo!(),
             }
         }
 
         fn read_data<T2: 'static + Serializer + ForyDefault>(
             context: &mut ReadContext,
-            is_field: bool,
         ) -> Result<Box<dyn Any>, Error> {
-            match T2::fory_read_data(context, is_field) {
+            match T2::fory_read_data(context) {
                 Ok(v) => Ok(Box::new(v)),
                 Err(e) => Err(e),
             }
@@ -549,62 +640,85 @@ impl TypeResolver {
         ) -> Result<Box<dyn Serializer>, Error> {
             match boxed_any.downcast::<T2>() {
                 Ok(concrete) => Ok(Box::new(*concrete) as Box<dyn Serializer>),
-                Err(_) => Err(Error::TypeError(
-                    "Failed to downcast to concrete type".into(),
-                )),
+                Err(_) => Err(Error::type_error("Failed to downcast to concrete type")),
             }
         }
 
+        let harness = Harness::new(
+            write::<T>,
+            read::<T>,
+            write_data::<T>,
+            read_data::<T>,
+            to_serializer::<T>,
+        );
+
+        let type_info = TypeInfo::new_with_empty_fields::<T>(
+            self,
+            actual_type_id,
+            namespace,
+            type_name,
+            register_by_name,
+            harness,
+        )?;
+
         let rs_type_id = std::any::TypeId::of::<T>();
-        if self.type_info_cache.contains_key(&rs_type_id) {
-            return Err(Error::TypeError(
-                format!("rs_struct:{:?} already registered", rs_type_id).into(),
-            ));
+        if self.type_info_map.contains_key(&rs_type_id) {
+            return Err(Error::type_error(format!(
+                "rs_struct:{:?} already registered",
+                rs_type_id
+            )));
         }
-        self.type_info_cache.insert(rs_type_id, type_info.clone());
+
+        // Store in main map
+        self.type_info_map
+            .insert(rs_type_id, Arc::new(type_info.clone()));
+
+        // Store by ID
+        self.type_info_map_by_id
+            .insert(type_info.type_id, Arc::new(type_info.clone()));
+
+        // Store by name if registered by name
         if type_info.register_by_name {
             let namespace = &type_info.namespace;
             let type_name = &type_info.type_name;
-            let key = (namespace.clone(), type_name.clone());
-            if self.name_serializer_map.contains_key(&key) {
-                return Err(Error::InvalidData(
-                    format!(
-                        "Namespace:{:?} Name:{:?} already registered_by_name",
-                        namespace, type_name
-                    )
-                    .into(),
-                ));
+            let ms_key = (namespace.clone(), type_name.clone());
+            if self.type_info_map_by_ms_name.contains_key(&ms_key) {
+                return Err(Error::invalid_data(format!(
+                    "Namespace:{:?} Name:{:?} already registered_by_name",
+                    namespace, type_name
+                )));
             }
-            self.type_name_map.insert(rs_type_id, key.clone());
-            self.name_serializer_map.insert(
-                key,
-                Arc::from(Harness::new(
-                    write::<T>,
-                    read::<T>,
-                    write_data::<T>,
-                    read_data::<T>,
-                    to_serializer::<T>,
-                )),
-            );
-        } else {
-            let type_id = type_info.type_id;
-            if self.serializer_map.contains_key(&type_id) {
-                return Err(Error::TypeError(
-                    format!("TypeId {:?} already registered_by_id", type_id).into(),
-                ));
-            }
-            self.type_id_map.insert(rs_type_id, type_id);
-            self.serializer_map.insert(
-                type_id,
-                Arc::from(Harness::new(
-                    write::<T>,
-                    read::<T>,
-                    write_data::<T>,
-                    read_data::<T>,
-                    to_serializer::<T>,
-                )),
-            );
+            self.type_info_map_by_ms_name
+                .insert(ms_key, Arc::new(type_info.clone()));
+            let string_key = (namespace.original.clone(), type_name.original.clone());
+            self.type_info_map_by_name
+                .insert(string_key, Arc::new(type_info));
         }
         Ok(())
     }
+
+    /// Register a generic trait type like List, Map, Set
+    pub fn register_generic_trait<T: 'static + Serializer + ForyDefault>(
+        &mut self,
+    ) -> Result<(), Error> {
+        let rs_type_id = std::any::TypeId::of::<T>();
+        if self.type_info_map.contains_key(&rs_type_id) {
+            return Err(Error::type_error(format!(
+                "Type:{:?} already registered",
+                rs_type_id
+            )));
+        }
+        let type_id = T::fory_static_type_id();
+        if type_id != TypeId::LIST && type_id != TypeId::MAP && type_id != TypeId::SET {
+            return Err(Error::not_allowed(format!(
+                "register_generic_trait can only be used for generic trait types: List, Map, Set, but got type {}",
+                type_id as u32
+            )));
+        }
+        self.register_internal_serializer::<T>(type_id)
+    }
+
+    pub(crate) fn set_compatible(&mut self, compatible: bool) {
+        self.compatible = compatible;
+    }
 }
diff --git a/rust/fory-core/src/row/row.rs b/rust/fory-core/src/row/row.rs
index 69795ce52..c215829c3 100644
--- a/rust/fory-core/src/row/row.rs
+++ b/rust/fory-core/src/row/row.rs
@@ -101,9 +101,9 @@ impl Row<'_> for NaiveDate {
         let days = LittleEndian::read_u32(bytes);
         EPOCH
             .checked_add_days(Days::new(days.into()))
-            .ok_or(Error::InvalidData(
-                format!("Date out of range, {days} days since epoch").into(),
-            ))
+            .ok_or(Error::invalid_data(format!(
+                "Date out of range, {days} days since epoch"
+            )))
     }
 }
 
@@ -119,9 +119,9 @@ impl Row<'_> for NaiveDateTime {
         let timestamp = LittleEndian::read_u64(bytes);
         DateTime::from_timestamp_millis(timestamp as i64)
             .map(|dt| dt.naive_utc())
-            .ok_or(Error::InvalidData(
-                format!("Date out of range, timestamp:{timestamp}").into(),
-            ))
+            .ok_or(Error::invalid_data(format!(
+                "Date out of range, timestamp:{timestamp}"
+            )))
     }
 }
 
diff --git a/rust/fory-core/src/serializer/any.rs b/rust/fory-core/src/serializer/any.rs
index 1bbfd5d3a..615d86f4e 100644
--- a/rust/fory-core/src/serializer/any.rs
+++ b/rust/fory-core/src/serializer/any.rs
@@ -15,41 +15,28 @@
 // specific language governing permissions and limitations
 // under the License.
 
+use crate::ensure;
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
+use crate::serializer::util::write_dyn_data_generic;
 use crate::serializer::{ForyDefault, Serializer};
 use crate::types::RefFlag;
+use crate::types::TypeId;
 use std::any::Any;
 use std::rc::Rc;
 use std::sync::Arc;
 
-/// Helper function to serialize a `Box<dyn Any>`
-pub fn serialize_any_box(
-    any_box: &Box<dyn Any>,
-    context: &mut WriteContext,
-    is_field: bool,
-) -> Result<(), Error> {
-    context.writer.write_i8(RefFlag::NotNullValue as i8);
-
-    let concrete_type_id = (**any_box).type_id();
-    let harness = context.write_any_typeinfo(concrete_type_id)?;
-    let serializer_fn = harness.get_write_data_fn();
-    serializer_fn(&**any_box, context, is_field)
-}
-
 /// Helper function to deserialize to `Box<dyn Any>`
 pub fn deserialize_any_box(context: &mut ReadContext) -> Result<Box<dyn Any>, Error> {
     context.inc_depth()?;
     let ref_flag = context.reader.read_i8()?;
     if ref_flag != RefFlag::NotNullValue as i8 {
-        return Err(Error::InvalidRef(
-            "Expected NotNullValue for Box<dyn Any>".into(),
-        ));
+        return Err(Error::invalid_ref("Expected NotNullValue for Box<dyn Any>"));
     }
-    let harness = context.read_any_typeinfo()?;
-    let deserializer_fn = harness.get_read_data_fn();
-    let result = deserializer_fn(context, true);
+    let typeinfo = context.read_any_typeinfo()?;
+    let deserializer_fn = typeinfo.get_harness().get_read_data_fn();
+    let result = deserializer_fn(context);
     context.dec_depth();
     result
 }
@@ -61,44 +48,98 @@ impl ForyDefault for Box<dyn Any> {
 }
 
 impl Serializer for Box<dyn Any> {
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        serialize_any_box(self, context, is_field)
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_typeinfo: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        write_box_any(
+            self.as_ref(),
+            context,
+            write_ref_info,
+            write_typeinfo,
+            has_generics,
+        )
+    }
+
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        let concrete_type_id = (**self).type_id();
+        let typeinfo = context.get_type_info(&concrete_type_id)?;
+        let serializer_fn = typeinfo.get_harness().get_write_data_fn();
+        serializer_fn(&**self, context, has_generics)
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        serialize_any_box(self, context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        self.fory_write_data_generic(context, false)
     }
 
-    fn fory_read(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        deserialize_any_box(context)
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        read_box_any(context, read_ref_info, read_type_info, None)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        deserialize_any_box(context)
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        read_box_any(context, read_ref_info, false, Some(type_info))
+    }
+
+    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
+        panic!(
+            "fory_read_data should not be called directly on polymorphic Rc<dyn Any> trait object"
+        );
     }
 
     fn fory_get_type_id(_: &TypeResolver) -> Result<u32, Error> {
-        unreachable!("Box<dyn Any> has no static type ID - use fory_type_id_dyn")
+        Err(Error::type_error(
+            "Box<dyn Any> has no static type ID - use fory_type_id_dyn",
+        ))
     }
 
     fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32, Error> {
         let concrete_type_id = (**self).type_id();
         type_resolver
             .get_fory_type_id(concrete_type_id)
-            .ok_or_else(|| Error::TypeError("Type not registered".into()))
+            .ok_or_else(|| Error::type_error("Type not registered"))
+    }
+
+    fn fory_concrete_type_id(&self) -> std::any::TypeId {
+        (**self).type_id()
     }
 
     fn fory_is_polymorphic() -> bool {
         true
     }
 
-    fn fory_write_type_info(_context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
-        // Rc<dyn Any> is polymorphic - type info is written per element
+    fn fory_is_shared_ref() -> bool {
+        false
+    }
+
+    fn fory_static_type_id() -> TypeId {
+        TypeId::UNKNOWN
+    }
+
+    fn fory_write_type_info(_context: &mut WriteContext) -> Result<(), Error> {
+        // Box<dyn Any> is polymorphic - type info is written per element
         Ok(())
     }
 
-    fn fory_read_type_info(_context: &mut ReadContext, _is_field: bool) -> Result<(), Error> {
-        // Rc<dyn Any> is polymorphic - type info is read per element
+    fn fory_read_type_info(_context: &mut ReadContext) -> Result<(), Error> {
+        // Box<dyn Any> is polymorphic - type info is read per element
         Ok(())
     }
 
@@ -107,6 +148,58 @@ impl Serializer for Box<dyn Any> {
     }
 }
 
+pub fn write_box_any(
+    value: &dyn Any,
+    context: &mut WriteContext,
+    write_ref_info: bool,
+    write_typeinfo: bool,
+    has_generics: bool,
+) -> Result<(), Error> {
+    if write_ref_info {
+        context.writer.write_i8(RefFlag::NotNullValue as i8);
+    }
+    let concrete_type_id = value.type_id();
+    let typeinfo = if write_typeinfo {
+        context.write_any_typeinfo(TypeId::UNKNOWN as u32, concrete_type_id)?
+    } else {
+        context.get_type_info(&concrete_type_id)?
+    };
+    let serializer_fn = typeinfo.get_harness().get_write_data_fn();
+    serializer_fn(value, context, has_generics)
+}
+
+pub fn read_box_any(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    type_info: Option<Arc<TypeInfo>>,
+) -> Result<Box<dyn Any>, Error> {
+    context.inc_depth()?;
+    let ref_flag = if read_ref_info {
+        context.reader.read_i8()?
+    } else {
+        RefFlag::NotNullValue as i8
+    };
+    if ref_flag != RefFlag::NotNullValue as i8 {
+        return Err(Error::invalid_data(
+            "Expected NotNullValue for Box<dyn Any>",
+        ));
+    }
+    let typeinfo = if let Some(type_info) = type_info {
+        type_info
+    } else {
+        ensure!(
+            read_type_info,
+            Error::invalid_data("Type info must be read for Box<dyn Any>")
+        );
+        context.read_any_typeinfo()?
+    };
+    let deserializer_fn = typeinfo.get_harness().get_read_data_fn();
+    let result = deserializer_fn(context);
+    context.dec_depth();
+    result
+}
+
 impl ForyDefault for Rc<dyn Any> {
     fn fory_default() -> Self {
         Rc::new(())
@@ -114,85 +207,107 @@ impl ForyDefault for Rc<dyn Any> {
 }
 
 impl Serializer for Rc<dyn Any> {
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        if !context
-            .ref_writer
-            .try_write_rc_ref(&mut context.writer, self)
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        if !write_ref_info
+            || !context
+                .ref_writer
+                .try_write_rc_ref(&mut context.writer, self)
         {
-            let concrete_type_id = (**self).type_id();
-            let harness = context.write_any_typeinfo(concrete_type_id)?;
-            let serializer_fn = harness.get_write_data_fn();
-            serializer_fn(&**self, context, is_field)?
-        };
+            let concrete_type_id: std::any::TypeId = (**self).type_id();
+            let write_data_fn = if write_type_info {
+                let typeinfo =
+                    context.write_any_typeinfo(TypeId::UNKNOWN as u32, concrete_type_id)?;
+                typeinfo.get_harness().get_write_data_fn()
+            } else {
+                context
+                    .get_type_info(&concrete_type_id)?
+                    .get_harness()
+                    .get_write_data_fn()
+            };
+            write_data_fn(&**self, context, has_generics)?;
+        }
         Ok(())
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        self.fory_write(context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_dyn_data_generic(self, context, false)
     }
 
-    fn fory_read(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        write_dyn_data_generic(self, context, has_generics)
+    }
 
-        match ref_flag {
-            RefFlag::Null => Err(Error::InvalidRef("Rc<dyn Any> cannot be null".into())),
-            RefFlag::Ref => {
-                let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
-                context
-                    .ref_reader
-                    .get_rc_ref::<dyn Any>(ref_id)
-                    .ok_or_else(|| {
-                        Error::InvalidData(
-                            format!("Rc<dyn Any> reference {} not found", ref_id).into(),
-                        )
-                    })
-            }
-            RefFlag::NotNullValue => {
-                context.inc_depth()?;
-                let harness = context.read_any_typeinfo()?;
-                let deserializer_fn = harness.get_read_data_fn();
-                let boxed = deserializer_fn(context, true)?;
-                context.dec_depth();
-                Ok(Rc::<dyn Any>::from(boxed))
-            }
-            RefFlag::RefValue => {
-                context.inc_depth()?;
-                let harness = context.read_any_typeinfo()?;
-                let deserializer_fn = harness.get_read_data_fn();
-                let boxed = deserializer_fn(context, true)?;
-                context.dec_depth();
-                let rc: Rc<dyn Any> = Rc::from(boxed);
-                context.ref_reader.store_rc_ref(rc.clone());
-                Ok(rc)
-            }
-        }
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        read_rc_any(context, read_ref_info, read_type_info, None)
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Self::fory_read(context, is_field)
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        read_rc_any(context, read_ref_info, false, Some(type_info))
+    }
+
+    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
+        panic!(
+            "fory_read_data should not be called directly on polymorphic Rc<dyn {}> trait object",
+            stringify!($trait_name)
+        );
     }
 
     fn fory_get_type_id(_: &TypeResolver) -> Result<u32, Error> {
-        unreachable!("Rc<dyn Any> has no static type ID - use fory_type_id_dyn")
+        Err(Error::type_error(
+            "Rc<dyn Any> has no static type ID - use fory_type_id_dyn",
+        ))
     }
 
     fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32, Error> {
         let concrete_type_id = (**self).type_id();
         type_resolver
             .get_fory_type_id(concrete_type_id)
-            .ok_or_else(|| Error::TypeError("Type not registered".into()))
+            .ok_or_else(|| Error::type_error("Type not registered"))
+    }
+
+    fn fory_concrete_type_id(&self) -> std::any::TypeId {
+        (**self).type_id()
+    }
+
+    fn fory_is_shared_ref() -> bool {
+        true
     }
 
     fn fory_is_polymorphic() -> bool {
         true
     }
 
-    fn fory_write_type_info(_context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_static_type_id() -> TypeId {
+        TypeId::UNKNOWN
+    }
+
+    fn fory_write_type_info(_context: &mut WriteContext) -> Result<(), Error> {
         // Rc<dyn Any> is polymorphic - type info is written per element
         Ok(())
     }
 
-    fn fory_read_type_info(_context: &mut ReadContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_read_type_info(_context: &mut ReadContext) -> Result<(), Error> {
         // Rc<dyn Any> is polymorphic - type info is read per element
         Ok(())
     }
@@ -202,6 +317,57 @@ impl Serializer for Rc<dyn Any> {
     }
 }
 
+pub fn read_rc_any(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    type_info: Option<Arc<TypeInfo>>,
+) -> Result<Rc<dyn Any>, Error> {
+    let ref_flag = if read_ref_info {
+        context.ref_reader.read_ref_flag(&mut context.reader)?
+    } else {
+        RefFlag::NotNullValue
+    };
+    match ref_flag {
+        RefFlag::Null => Err(Error::invalid_ref("Rc<dyn Any> cannot be null")),
+        RefFlag::Ref => {
+            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
+            context
+                .ref_reader
+                .get_rc_ref::<dyn Any>(ref_id)
+                .ok_or_else(|| {
+                    Error::invalid_data(format!("Rc<dyn Any> reference {} not found", ref_id))
+                })
+        }
+        RefFlag::NotNullValue => {
+            context.inc_depth()?;
+            let typeinfo = if read_type_info {
+                context.read_any_typeinfo()?
+            } else {
+                type_info.ok_or_else(|| Error::type_error("No type info found for read"))?
+            };
+            let read_data_fn = typeinfo.get_harness().get_read_data_fn();
+            let boxed = read_data_fn(context)?;
+            context.dec_depth();
+            Ok(Rc::<dyn Any>::from(boxed))
+        }
+        RefFlag::RefValue => {
+            context.inc_depth()?;
+            let typeinfo = if read_type_info {
+                context.read_any_typeinfo()?
+            } else {
+                type_info.ok_or_else(|| Error::type_error("No type info found for read"))?
+            };
+            let read_data_fn = typeinfo.get_harness().get_read_data_fn();
+            let boxed = read_data_fn(context)?;
+            context.dec_depth();
+            let rc: Rc<dyn Any> = Rc::from(boxed);
+            context.ref_reader.store_rc_ref(rc.clone());
+            Ok(rc)
+        }
+    }
+}
+
 impl ForyDefault for Arc<dyn Any> {
     fn fory_default() -> Self {
         Arc::new(())
@@ -209,85 +375,108 @@ impl ForyDefault for Arc<dyn Any> {
 }
 
 impl Serializer for Arc<dyn Any> {
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        if !context
-            .ref_writer
-            .try_write_arc_ref(&mut context.writer, self)
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        if !write_ref_info
+            || !context
+                .ref_writer
+                .try_write_arc_ref(&mut context.writer, self)
         {
-            let concrete_type_id = (**self).type_id();
-            let harness = context.write_any_typeinfo(concrete_type_id)?;
-            let serializer_fn = harness.get_write_data_fn();
-            serializer_fn(&**self, context, is_field)?;
+            let concrete_type_id: std::any::TypeId = (**self).type_id();
+            if write_type_info {
+                let typeinfo =
+                    context.write_any_typeinfo(TypeId::UNKNOWN as u32, concrete_type_id)?;
+                let serializer_fn = typeinfo.get_harness().get_write_data_fn();
+                serializer_fn(&**self, context, has_generics)?;
+            } else {
+                let serializer_fn = context
+                    .get_type_info(&concrete_type_id)?
+                    .get_harness()
+                    .get_write_data_fn();
+                serializer_fn(&**self, context, has_generics)?;
+            }
         }
         Ok(())
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        self.fory_write(context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_dyn_data_generic(self, context, false)
     }
 
-    fn fory_read(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        write_dyn_data_generic(self, context, has_generics)
+    }
 
-        match ref_flag {
-            RefFlag::Null => Err(Error::InvalidRef("Arc<dyn Any> cannot be null".into())),
-            RefFlag::Ref => {
-                let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
-                context
-                    .ref_reader
-                    .get_arc_ref::<dyn Any>(ref_id)
-                    .ok_or_else(|| {
-                        Error::InvalidData(
-                            format!("Arc<dyn Any> reference {} not found", ref_id).into(),
-                        )
-                    })
-            }
-            RefFlag::NotNullValue => {
-                context.inc_depth()?;
-                let harness = context.read_any_typeinfo()?;
-                let deserializer_fn = harness.get_read_data_fn();
-                let boxed = deserializer_fn(context, true)?;
-                context.dec_depth();
-                Ok(Arc::<dyn Any>::from(boxed))
-            }
-            RefFlag::RefValue => {
-                context.inc_depth()?;
-                let harness = context.read_any_typeinfo()?;
-                let deserializer_fn = harness.get_read_data_fn();
-                let boxed = deserializer_fn(context, true)?;
-                context.dec_depth();
-                let arc: Arc<dyn Any> = Arc::from(boxed);
-                context.ref_reader.store_arc_ref(arc.clone());
-                Ok(arc)
-            }
-        }
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        read_arc_any(context, read_ref_info, read_type_info, None)
+    }
+
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        read_arc_any(context, read_ref_info, false, Some(type_info))
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Self::fory_read(context, is_field)
+    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
+        panic!(
+            "fory_read_data should not be called directly on polymorphic Rc<dyn {}> trait object",
+            stringify!($trait_name)
+        );
     }
 
     fn fory_get_type_id(_type_resolver: &TypeResolver) -> Result<u32, Error> {
-        unreachable!("Arc<dyn Any> has no static type ID - use fory_type_id_dyn")
+        Err(Error::type_error(
+            "Arc<dyn Any> has no static type ID - use fory_type_id_dyn",
+        ))
     }
 
     fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32, Error> {
         let concrete_type_id = (**self).type_id();
         type_resolver
             .get_fory_type_id(concrete_type_id)
-            .ok_or_else(|| Error::TypeError("Type not registered".into()))
+            .ok_or_else(|| Error::type_error("Type not registered"))
+    }
+
+    fn fory_concrete_type_id(&self) -> std::any::TypeId {
+        (**self).type_id()
     }
 
     fn fory_is_polymorphic() -> bool {
         true
     }
 
-    fn fory_write_type_info(_context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_is_shared_ref() -> bool {
+        true
+    }
+
+    fn fory_static_type_id() -> TypeId {
+        TypeId::UNKNOWN
+    }
+
+    fn fory_write_type_info(_context: &mut WriteContext) -> Result<(), Error> {
         // Arc<dyn Any> is polymorphic - type info is written per element
         Ok(())
     }
 
-    fn fory_read_type_info(_context: &mut ReadContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_read_type_info(_context: &mut ReadContext) -> Result<(), Error> {
         // Arc<dyn Any> is polymorphic - type info is read per element
         Ok(())
     }
@@ -296,3 +485,56 @@ impl Serializer for Arc<dyn Any> {
         &**self
     }
 }
+
+pub fn read_arc_any(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    type_info: Option<Arc<TypeInfo>>,
+) -> Result<Arc<dyn Any>, Error> {
+    let ref_flag = if read_ref_info {
+        context.ref_reader.read_ref_flag(&mut context.reader)?
+    } else {
+        RefFlag::NotNullValue
+    };
+    match ref_flag {
+        RefFlag::Null => Err(Error::invalid_ref("Arc<dyn Any> cannot be null")),
+        RefFlag::Ref => {
+            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
+            context
+                .ref_reader
+                .get_arc_ref::<dyn Any>(ref_id)
+                .ok_or_else(|| {
+                    Error::invalid_data(format!("Arc<dyn Any> reference {} not found", ref_id))
+                })
+        }
+        RefFlag::NotNullValue => {
+            context.inc_depth()?;
+            let typeinfo = if read_type_info {
+                context.read_any_typeinfo()?
+            } else {
+                type_info
+                    .ok_or_else(|| Error::type_error("No type info found for read Arc<dyn Any>"))?
+            };
+            let read_data_fn = typeinfo.get_harness().get_read_data_fn();
+            let boxed = read_data_fn(context)?;
+            context.dec_depth();
+            Ok(Arc::<dyn Any>::from(boxed))
+        }
+        RefFlag::RefValue => {
+            context.inc_depth()?;
+            let typeinfo = if read_type_info {
+                context.read_any_typeinfo()?
+            } else {
+                type_info
+                    .ok_or_else(|| Error::type_error("No type info found for read Arc<dyn Any>"))?
+            };
+            let read_data_fn = typeinfo.get_harness().get_read_data_fn();
+            let boxed = read_data_fn(context)?;
+            context.dec_depth();
+            let arc: Arc<dyn Any> = Arc::from(boxed);
+            context.ref_reader.store_arc_ref(arc.clone());
+            Ok(arc)
+        }
+    }
+}
diff --git a/rust/fory-core/src/serializer/arc.rs b/rust/fory-core/src/serializer/arc.rs
index e4cbda85e..33eddff2c 100644
--- a/rust/fory-core/src/serializer/arc.rs
+++ b/rust/fory-core/src/serializer/arc.rs
@@ -17,9 +17,10 @@
 
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 use crate::serializer::{ForyDefault, Serializer};
 use crate::types::RefFlag;
+use crate::types::TypeId;
 use std::sync::Arc;
 
 impl<T: Serializer + ForyDefault + Send + Sync + 'static> Serializer for Arc<T> {
@@ -27,63 +28,75 @@ impl<T: Serializer + ForyDefault + Send + Sync + 'static> Serializer for Arc<T>
         true
     }
 
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        if !context
-            .ref_writer
-            .try_write_arc_ref(&mut context.writer, self)
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        if !write_ref_info
+            || !context
+                .ref_writer
+                .try_write_arc_ref(&mut context.writer, self)
         {
-            T::fory_write_data(self.as_ref(), context, is_field)?
-        };
-        Ok(())
+            if T::fory_is_shared_ref() || T::fory_is_polymorphic() {
+                let inner_write_ref = T::fory_is_shared_ref();
+                return T::fory_write(
+                    &**self,
+                    context,
+                    inner_write_ref,
+                    write_type_info,
+                    has_generics,
+                );
+            }
+            if write_type_info {
+                T::fory_write_type_info(context)?;
+            }
+            T::fory_write_data_generic(self, context, has_generics)
+        } else {
+            Ok(())
+        }
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        // When Arc is nested inside another shared ref (like Rc<Arc<T>>),
-        // the outer ref calls fory_write_data on the inner Arc.
-        // We still need to track the Arc's own references here.
-        self.fory_write(context, is_field)
+    fn fory_write_data_generic(&self, _: &mut WriteContext, _: bool) -> Result<(), Error> {
+        panic!("Arc<T> should be written using `fory_write` to handle reference tracking properly");
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_write_data(&self, _: &mut WriteContext) -> Result<(), Error> {
+        panic!("Arc<T> should be written using `fory_write` to handle reference tracking properly");
     }
 
-    fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
+    }
 
-        Ok(match ref_flag {
-            RefFlag::Null => Err(Error::InvalidRef("Arc cannot be null".into()))?,
-            RefFlag::Ref => {
-                let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
-                context
-                    .ref_reader
-                    .get_arc_ref::<T>(ref_id)
-                    .ok_or(Error::InvalidData(
-                        format!("Arc reference {ref_id} not found").into(),
-                    ))?
-            }
-            RefFlag::NotNullValue => {
-                let inner = T::fory_read_data(context, is_field)?;
-                Arc::new(inner)
-            }
-            RefFlag::RefValue => {
-                let ref_id = context.ref_reader.reserve_ref_id();
-                let inner = T::fory_read_data(context, is_field)?;
-                let arc = Arc::new(inner);
-                context.ref_reader.store_arc_ref_at(ref_id, arc.clone());
-                arc
-            }
-        })
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        // if read_ref_info is false, shared refs will be deserialized into new objects each time.
+        read_arc(context, read_ref_info, read_type_info, None)
+    }
+
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        typeinfo: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        read_arc(context, read_ref_info, false, Some(typeinfo))
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        // When Arc is nested inside another shared ref, fory_read_data is called.
-        // Delegate to fory_read which handles ref tracking properly.
-        Self::fory_read(context, is_field)
+    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
+        panic!("Arc<T> should be read using `fory_read/fory_read_with_type_info` to handle reference tracking properly");
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
     }
 
     fn fory_reserved_space() -> usize {
@@ -100,11 +113,68 @@ impl<T: Serializer + ForyDefault + Send + Sync + 'static> Serializer for Arc<T>
         (**self).fory_type_id_dyn(type_resolver)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        T::fory_static_type_id()
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 }
 
+fn read_arc<T: Serializer + ForyDefault + 'static>(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    typeinfo: Option<Arc<TypeInfo>>,
+) -> Result<Arc<T>, Error> {
+    let ref_flag = if read_ref_info {
+        context.ref_reader.read_ref_flag(&mut context.reader)?
+    } else {
+        RefFlag::NotNullValue
+    };
+    match ref_flag {
+        RefFlag::Null => Err(Error::invalid_ref("Arc cannot be null")),
+        RefFlag::Ref => {
+            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
+            context
+                .ref_reader
+                .get_arc_ref::<T>(ref_id)
+                .ok_or_else(|| Error::invalid_ref(format!("Arc reference {ref_id} not found")))
+        }
+        RefFlag::NotNullValue => {
+            let inner = read_arc_inner::<T>(context, read_type_info, typeinfo)?;
+            Ok(Arc::new(inner))
+        }
+        RefFlag::RefValue => {
+            let ref_id = context.ref_reader.reserve_ref_id();
+            let inner = read_arc_inner::<T>(context, read_type_info, typeinfo)?;
+            let arc = Arc::new(inner);
+            context.ref_reader.store_arc_ref_at(ref_id, arc.clone());
+            Ok(arc)
+        }
+    }
+}
+
+fn read_arc_inner<T: Serializer + ForyDefault + 'static>(
+    context: &mut ReadContext,
+    read_type_info: bool,
+    typeinfo: Option<Arc<TypeInfo>>,
+) -> Result<T, Error> {
+    if let Some(typeinfo) = typeinfo {
+        let inner_read_ref = T::fory_is_shared_ref();
+        return T::fory_read_with_type_info(context, inner_read_ref, typeinfo);
+    }
+    if T::fory_is_shared_ref() || T::fory_is_polymorphic() {
+        let inner_read_ref = T::fory_is_shared_ref();
+        return T::fory_read(context, inner_read_ref, read_type_info);
+    }
+    if read_type_info {
+        T::fory_read_type_info(context)?;
+    }
+    T::fory_read_data(context)
+}
+
 impl<T: ForyDefault> ForyDefault for Arc<T> {
     fn fory_default() -> Self {
         Arc::new(T::fory_default())
diff --git a/rust/fory-core/src/serializer/bool.rs b/rust/fory-core/src/serializer/bool.rs
index 9c1642bcd..5dac06404 100644
--- a/rust/fory-core/src/serializer/bool.rs
+++ b/rust/fory-core/src/serializer/bool.rs
@@ -19,19 +19,20 @@ use crate::error::Error;
 use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
-use crate::serializer::{read_type_info, write_type_info, ForyDefault, Serializer};
+use crate::serializer::util::read_basic_type_info;
+use crate::serializer::{ForyDefault, Serializer};
 use crate::types::TypeId;
 use std::mem;
 
 impl Serializer for bool {
     #[inline(always)]
-    fn fory_write_data(&self, context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
         context.writer.write_u8(if *self { 1 } else { 0 });
         Ok(())
     }
 
     #[inline(always)]
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         Ok(context.reader.read_u8()? == 1)
     }
 
@@ -49,19 +50,24 @@ impl Serializer for bool {
         Ok(TypeId::BOOL as u32)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        TypeId::BOOL
+    }
+
     #[inline(always)]
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 
     #[inline(always)]
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_type_info::<Self>(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        context.writer.write_varuint32(TypeId::BOOL as u32);
+        Ok(())
     }
 
     #[inline(always)]
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_type_info::<Self>(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_basic_type_info::<Self>(context)
     }
 }
 
diff --git a/rust/fory-core/src/serializer/box_.rs b/rust/fory-core/src/serializer/box_.rs
index 6cf873007..79bd3c729 100644
--- a/rust/fory-core/src/serializer/box_.rs
+++ b/rust/fory-core/src/serializer/box_.rs
@@ -20,22 +20,26 @@ use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
 use crate::serializer::{ForyDefault, Serializer};
+use crate::types::TypeId;
 
 impl<T: Serializer + ForyDefault> Serializer for Box<T> {
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Ok(Box::new(T::fory_read_data(context, is_field)?))
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(Box::new(T::fory_read_data(context)?))
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_data(self.as_ref(), context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_data(self.as_ref(), context)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
     }
 
     fn fory_reserved_space() -> usize {
@@ -50,6 +54,10 @@ impl<T: Serializer + ForyDefault> Serializer for Box<T> {
         (**self).fory_type_id_dyn(type_resolver)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        T::fory_static_type_id()
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
diff --git a/rust/fory-core/src/serializer/collection.rs b/rust/fory-core/src/serializer/collection.rs
index 25469c589..cad0b5333 100644
--- a/rust/fory-core/src/serializer/collection.rs
+++ b/rust/fory-core/src/serializer/collection.rs
@@ -20,9 +20,9 @@ use crate::error::Error;
 use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::serializer::{ForyDefault, Serializer};
-use crate::types::PRIMITIVE_ARRAY_TYPES;
+use crate::types::{need_to_write_type_for_field, RefFlag, PRIMITIVE_ARRAY_TYPES};
 
-// const TRACKING_REF: u8 = 0b1;
+const TRACKING_REF: u8 = 0b1;
 
 pub const HAS_NULL: u8 = 0b10;
 
@@ -34,21 +34,16 @@ pub const IS_SAME_TYPE: u8 = 0b1000;
 
 pub fn write_collection_type_info(
     context: &mut WriteContext,
-    is_field: bool,
     collection_type_id: u32,
 ) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
-    }
     context.writer.write_varuint32(collection_type_id);
     Ok(())
 }
 
-pub fn write_collection<'a, T, I>(
+pub fn write_collection_data<'a, T, I>(
     iter: I,
-
     context: &mut WriteContext,
-    is_field: bool,
+    has_generics: bool,
 ) -> Result<(), Error>
 where
     T: Serializer + 'a,
@@ -61,9 +56,13 @@ where
     if len == 0 {
         return Ok(());
     }
-    let mut header = 0;
+    if T::fory_is_polymorphic() || T::fory_is_shared_ref() {
+        return write_collection_data_dyn_ref(iter, context, has_generics);
+    }
+    let mut header = IS_SAME_TYPE;
     let mut has_null = false;
-    let is_same_type = !T::fory_is_polymorphic();
+    let elem_static_type_id = T::fory_static_type_id();
+    let is_elem_declared = has_generics && !need_to_write_type_for_field(elem_static_type_id);
     if T::fory_is_option() {
         // iter.clone() is zero-copy
         for item in iter.clone() {
@@ -76,56 +75,164 @@ where
     if has_null {
         header |= HAS_NULL;
     }
-    if is_field {
+    if is_elem_declared {
+        header |= DECL_ELEMENT_TYPE;
+        context.writer.write_u8(header);
+    } else {
+        context.writer.write_u8(header);
+        T::fory_write_type_info(context)?;
+    }
+    if !has_null {
+        for item in iter {
+            item.fory_write_data_generic(context, has_generics)?;
+        }
+    } else {
+        for item in iter {
+            if item.fory_is_none() {
+                context.writer.write_u8(RefFlag::Null as u8);
+                continue;
+            }
+            context.writer.write_u8(RefFlag::NotNullValue as u8);
+            item.fory_write_data_generic(context, has_generics)?;
+        }
+    }
+
+    Ok(())
+}
+
+/// Slow but versatile collection serialization for dynamic trait object and shared/circular reference.
+pub fn write_collection_data_dyn_ref<'a, T, I>(
+    iter: I,
+    context: &mut WriteContext,
+    has_generics: bool,
+) -> Result<(), Error>
+where
+    T: Serializer + 'a,
+    I: IntoIterator<Item = &'a T>,
+    I::IntoIter: ExactSizeIterator + Clone,
+{
+    let elem_static_type_id = T::fory_static_type_id();
+    let is_elem_declared = has_generics && !need_to_write_type_for_field(elem_static_type_id);
+    let elem_is_polymorphic = T::fory_is_polymorphic();
+    let elem_is_shared_ref = T::fory_is_shared_ref();
+
+    let iter = iter.into_iter();
+    let mut has_null = false;
+    let mut is_same_type = true;
+    let mut first_type_id: Option<std::any::TypeId> = None;
+
+    for item in iter.clone() {
+        if item.fory_is_none() {
+            has_null = true;
+        } else if elem_is_polymorphic && is_same_type {
+            let concrete_id = item.fory_concrete_type_id();
+            if let Some(first_id) = first_type_id {
+                if first_id != concrete_id {
+                    is_same_type = false;
+                }
+            } else {
+                first_type_id = Some(concrete_id);
+            }
+        }
+    }
+
+    if elem_is_polymorphic && is_same_type && first_type_id.is_none() {
+        // All elements are null for a polymorphic collection; fallback to per-element typing.
+        is_same_type = false;
+    }
+
+    let mut header = 0u8;
+    if has_null {
+        header |= HAS_NULL;
+    }
+    if is_elem_declared {
         header |= DECL_ELEMENT_TYPE;
     }
     if is_same_type {
         header |= IS_SAME_TYPE;
     }
+    if elem_is_shared_ref {
+        header |= TRACKING_REF;
+    }
+
     context.writer.write_u8(header);
-    T::fory_write_type_info(context, is_field)?;
-    // context.writer.reserve((T::reserved_space() + SIZE_OF_REF_AND_TYPE) * len);
-    if T::fory_is_polymorphic() || T::fory_is_shared_ref() {
-        // TOTO: make it xlang compatible
-        for item in iter {
-            item.fory_write(context, is_field)?;
+
+    if is_same_type && !is_elem_declared {
+        if elem_is_polymorphic {
+            let type_id = first_type_id.ok_or_else(|| {
+                Error::type_error(
+                    "Unable to determine concrete type for polymorphic collection elements",
+                )
+            })?;
+            context.write_any_typeinfo(T::fory_static_type_id() as u32, type_id)?;
+        } else {
+            T::fory_write_type_info(context)?;
+        }
+    }
+    // Write elements data
+    if is_same_type {
+        // All elements are same type
+        if !has_null {
+            // No null elements
+            if elem_is_shared_ref {
+                for item in iter {
+                    item.fory_write(context, true, false, has_generics)?;
+                }
+            } else {
+                for item in iter {
+                    item.fory_write_data_generic(context, has_generics)?;
+                }
+            }
+        } else {
+            // Has null elements
+            for item in iter {
+                item.fory_write(context, true, false, has_generics)?;
+            }
         }
-        Ok(())
     } else {
-        // let skip_ref_flag = crate::serializer::get_skip_ref_flag::<T>(context.get_fory());
-        let skip_ref_flag = is_same_type && !has_null;
-        for item in iter {
-            crate::serializer::write_ref_info_data(item, context, is_field, skip_ref_flag, true)?;
+        // Different types (polymorphic elements with different types)
+        if !has_null {
+            // No null elements
+            if elem_is_shared_ref {
+                for item in iter {
+                    item.fory_write(context, true, true, has_generics)?;
+                }
+            } else {
+                for item in iter {
+                    item.fory_write(context, false, true, has_generics)?;
+                }
+            }
+        } else {
+            // Has null elements
+            for item in iter {
+                item.fory_write(context, true, true, has_generics)?;
+            }
         }
-        Ok(())
     }
+
+    Ok(())
 }
 
 pub fn read_collection_type_info(
     context: &mut ReadContext,
-    is_field: bool,
     collection_type_id: u32,
 ) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
-    }
     let remote_collection_type_id = context.reader.read_varuint32()?;
     if PRIMITIVE_ARRAY_TYPES.contains(&remote_collection_type_id) {
-        return Err(Error::TypeError(
+        return Err(Error::type_error(
             "Vec<number> belongs to the `number_array` type, \
             and Vec<Option<number>> belongs to the `list` type. \
-            You should not read data of type `number_array` as data of type `list`."
-                .into(),
+            You should not read data of type `number_array` as data of type `list`.",
         ));
     }
     ensure!(
         collection_type_id == remote_collection_type_id,
-        Error::TypeMismatch(collection_type_id, remote_collection_type_id)
+        Error::type_mismatch(collection_type_id, remote_collection_type_id)
     );
     Ok(())
 }
 
-pub fn read_collection<C, T>(context: &mut ReadContext) -> Result<C, Error>
+pub fn read_collection_data<C, T>(context: &mut ReadContext) -> Result<C, Error>
 where
     T: Serializer + ForyDefault,
     C: FromIterator<T>,
@@ -134,20 +241,84 @@ where
     if len == 0 {
         return Ok(C::from_iter(std::iter::empty()));
     }
+    if T::fory_is_polymorphic() || T::fory_is_shared_ref() {
+        return read_collection_data_dyn_ref(context, len);
+    }
     let header = context.reader.read_u8()?;
     let declared = (header & DECL_ELEMENT_TYPE) != 0;
-    T::fory_read_type_info(context, declared)?;
+    if !declared {
+        // context.read_any_typeinfo();
+        // TODO check whether type info consistent with T
+        T::fory_read_type_info(context)?;
+    }
     let has_null = (header & HAS_NULL) != 0;
-    let is_same_type = (header & IS_SAME_TYPE) != 0;
-    if T::fory_is_polymorphic() || T::fory_is_shared_ref() {
+    ensure!(
+        (header & IS_SAME_TYPE) != 0,
+        Error::type_error("Type inconsistent, target type is not polymorphic")
+    );
+    if !has_null {
         (0..len)
-            .map(|_| T::fory_read(context, declared))
+            .map(|_| T::fory_read_data(context))
             .collect::<Result<C, Error>>()
     } else {
-        let skip_ref_flag = is_same_type && !has_null;
-        // let skip_ref_flag = crate::serializer::get_skip_ref_flag::<T>(context.get_fory());
         (0..len)
-            .map(|_| crate::serializer::read_ref_info_data(context, declared, skip_ref_flag, true))
+            .map(|_| {
+                let flag = context.reader.read_i8()?;
+                if flag == RefFlag::Null as i8 {
+                    return Ok(T::fory_default());
+                }
+                T::fory_read_data(context)
+            })
+            .collect::<Result<C, Error>>()
+    }
+}
+
+/// Slow but versatile collection deserialization for dynamic trait object and shared/circular reference.
+pub fn read_collection_data_dyn_ref<C, T>(context: &mut ReadContext, len: u32) -> Result<C, Error>
+where
+    T: Serializer + ForyDefault,
+    C: FromIterator<T>,
+{
+    // Read header
+    let header = context.reader.read_u8()?;
+    let is_track_ref = (header & TRACKING_REF) != 0;
+    let is_same_type = (header & IS_SAME_TYPE) != 0;
+    let has_null = (header & HAS_NULL) != 0;
+    let is_declared = (header & DECL_ELEMENT_TYPE) != 0;
+    // Read elements
+    if is_same_type {
+        let type_info = if !is_declared {
+            context.read_any_typeinfo()?
+        } else {
+            let rs_type_id = std::any::TypeId::of::<T>();
+            context.get_type_resolver().get_type_info(&rs_type_id)?
+        };
+        // All elements are same type
+        if is_track_ref {
+            (0..len)
+                .map(|_| T::fory_read_with_type_info(context, true, type_info.clone()))
+                .collect::<Result<C, Error>>()
+        } else if !has_null {
+            // No null elements
+            (0..len)
+                .map(|_| T::fory_read_with_type_info(context, false, type_info.clone()))
+                .collect::<Result<C, Error>>()
+        } else {
+            // Has null elements
+            (0..len)
+                .map(|_| {
+                    let flag = context.reader.read_i8()?;
+                    if flag == RefFlag::Null as i8 {
+                        Ok(T::fory_default())
+                    } else {
+                        T::fory_read_with_type_info(context, false, type_info.clone())
+                    }
+                })
+                .collect::<Result<C, Error>>()
+        }
+    } else {
+        (0..len)
+            .map(|_| T::fory_read(context, is_track_ref, true))
             .collect::<Result<C, Error>>()
     }
 }
diff --git a/rust/fory-core/src/serializer/core.rs b/rust/fory-core/src/serializer/core.rs
new file mode 100644
index 000000000..f2ac8f7a6
--- /dev/null
+++ b/rust/fory-core/src/serializer/core.rs
@@ -0,0 +1,276 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::error::Error;
+use crate::meta::FieldInfo;
+use crate::resolver::context::{ReadContext, WriteContext};
+use crate::resolver::type_resolver::TypeInfo;
+use crate::serializer::{bool, struct_};
+use crate::types::{RefFlag, TypeId};
+use crate::TypeResolver;
+use std::any::Any;
+use std::sync::Arc;
+
+pub trait ForyDefault: Sized {
+    fn fory_default() -> Self;
+}
+
+// We can't add blanket impl for all T: Default because it conflicts with other impls.
+// For example, upstream crates may add a new impl of trait `std::default::Default` for
+// type `std::rc::Rc<(dyn std::any::Any + 'static)>` in future versions.
+// impl<T: Default + Sized> ForyDefault for T {
+//     fn fory_default() -> Self {
+//         Default::default()
+//     }
+// }
+
+pub trait Serializer: 'static {
+    /// Entry point of the serialization.
+    ///
+    /// # Parameters
+    ///
+    /// * `write_ref_info` - When `true`, WRITES reference flag (null/not-null/ref). When `false`, SKIPS writing ref flag.
+    /// * `write_type_info` - When `true`, WRITES type information. When `false`, SKIPS writing type info.
+    /// * `has_generics` - Indicates if the type has generic parameters (used for collection meta).
+    ///
+    /// # Notes
+    ///
+    /// Serializer for `option/rc/arc/weak` should override this method.
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error>
+    where
+        Self: Sized,
+    {
+        if write_ref_info {
+            // skip check option/pointer, the Serializer for such types will override `fory_write`.
+            context.writer.write_i8(RefFlag::NotNullValue as i8);
+        }
+        if write_type_info {
+            // Serializer for dynamic types should override `fory_write` to write actual typeinfo.
+            Self::fory_write_type_info(context)?;
+        }
+        self.fory_write_data_generic(context, has_generics)
+    }
+
+    /// Write the data into the buffer. Need to be implemented for collection/map.
+    /// For other types, just forward to `fory_write_data`.
+    #[allow(unused_variables)]
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        self.fory_write_data(context)
+    }
+
+    /// Write the data into the buffer. Need to be implemented.
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error>;
+
+    #[inline(always)]
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error>
+    where
+        Self: Sized,
+    {
+        // Serializer for internal types should overwrite this method for faster performance.
+        let rs_type_id = std::any::TypeId::of::<Self>();
+        context.write_any_typeinfo(Self::fory_static_type_id() as u32, rs_type_id)?;
+        Ok(())
+    }
+
+    /// Entry point of deserialization.
+    ///
+    /// # Parameters
+    ///
+    /// * `read_ref_info` - When `true`, READS reference flag from buffer. When `false`, SKIPS reading ref flag.
+    /// * `read_type_info` - When `true`, READS type information from buffer. When `false`, SKIPS reading type info.
+    ///
+    /// # Notes
+    ///
+    /// Unlike `fory_write`, read doesn't need `has_generics` - it's only used for writing meta.
+    /// The meta info is already written in the buffer, so read can parse it directly to decide how to read the data.
+    /// Serializer for `option/rc/arc/weak` should override this method.
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        if read_ref_info {
+            let ref_flag = context.reader.read_i8()?;
+            match ref_flag {
+                flag if flag == RefFlag::Null as i8 => Ok(Self::fory_default()),
+                flag if flag == RefFlag::NotNullValue as i8 || flag == RefFlag::RefValue as i8 => {
+                    if read_type_info {
+                        Self::fory_read_type_info(context)?;
+                    }
+                    Self::fory_read_data(context)
+                }
+                flag if flag == RefFlag::Ref as i8 => {
+                    Err(Error::invalid_ref("Invalid ref, current type is not a ref"))
+                }
+                other => Err(Error::invalid_data(format!("Unknown ref flag: {}", other))),
+            }
+        } else {
+            if read_type_info {
+                Self::fory_read_type_info(context)?;
+            }
+            Self::fory_read_data(context)
+        }
+    }
+
+    /// Deserialization with pre-read type information.
+    ///
+    /// # Parameters
+    ///
+    /// * `read_ref_info` - When `true`, READS reference flag from buffer. When `false`, SKIPS reading ref flag.
+    /// * `type_info` - Type information that has already been read ahead. DO NOT read type info again from buffer.
+    ///
+    /// # Notes
+    ///
+    /// The type info has already been read and is passed as an argument, so this method should NOT read type info from the buffer.
+    /// Default implementation ignores the typeinfo, only for morphic types supported by fory directly
+    /// or ext type registered by user. Dynamic trait types or reference types should override this method.
+    #[allow(unused_variables)]
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        // Default implementation ignores the provided typeinfo because the static type matches.
+        // Honor the supplied `read_ref_info` flag so callers can control whether ref metadata is present.
+        Self::fory_read(context, read_ref_info, false)
+    }
+
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault;
+
+    #[inline(always)]
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error>
+    where
+        Self: Sized,
+    {
+        // Serializer for internal types should overwrite this method for faster performance.
+        context.read_any_typeinfo()?;
+        Ok(())
+    }
+
+    #[inline(always)]
+    fn fory_is_option() -> bool
+    where
+        Self: Sized,
+    {
+        false
+    }
+
+    #[inline(always)]
+    fn fory_is_none(&self) -> bool {
+        false
+    }
+
+    #[inline(always)]
+    fn fory_is_polymorphic() -> bool
+    where
+        Self: Sized,
+    {
+        false
+    }
+
+    #[inline(always)]
+    fn fory_is_shared_ref() -> bool
+    where
+        Self: Sized,
+    {
+        false
+    }
+
+    #[inline(always)]
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        // set to ext to simplify the user defined serializer.
+        // serializer for other types will override this method.
+        TypeId::EXT
+    }
+
+    #[inline(always)]
+    fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<u32, Error>
+    where
+        Self: Sized,
+    {
+        Ok(type_resolver
+            .get_type_info(&std::any::TypeId::of::<Self>())?
+            .get_type_id())
+    }
+
+    fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32, Error>;
+
+    #[inline(always)]
+    fn fory_concrete_type_id(&self) -> std::any::TypeId {
+        std::any::TypeId::of::<Self>()
+    }
+
+    /// The possible max memory size of the type.
+    /// Used to reserve the buffer space to avoid reallocation, which may hurt performance.
+    #[inline(always)]
+    fn fory_reserved_space() -> usize
+    where
+        Self: Sized,
+    {
+        0
+    }
+
+    fn as_any(&self) -> &dyn Any;
+}
+
+pub trait StructSerializer: Serializer + 'static {
+    #[allow(unused_variables)]
+    fn fory_fields_info(type_resolver: &TypeResolver) -> Result<Vec<FieldInfo>, Error> {
+        Ok(Vec::default())
+    }
+
+    fn fory_type_index() -> u32 {
+        unimplemented!()
+    }
+
+    fn fory_actual_type_id(type_id: u32, register_by_name: bool, compatible: bool) -> u32 {
+        struct_::actual_type_id(type_id, register_by_name, compatible)
+    }
+
+    fn fory_get_sorted_field_names() -> &'static [&'static str] {
+        &[]
+    }
+
+    // only used by struct
+    fn fory_read_compatible(
+        context: &mut ReadContext,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized;
+}
diff --git a/rust/fory-core/src/serializer/datetime.rs b/rust/fory-core/src/serializer/datetime.rs
index 7ef84a305..c5b65476f 100644
--- a/rust/fory-core/src/serializer/datetime.rs
+++ b/rust/fory-core/src/serializer/datetime.rs
@@ -19,31 +19,30 @@ use crate::error::Error;
 use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
+use crate::serializer::util::read_basic_type_info;
+use crate::serializer::ForyDefault;
 use crate::serializer::Serializer;
-use crate::serializer::{read_type_info, write_type_info, ForyDefault};
 use crate::types::TypeId;
 use crate::util::EPOCH;
-use chrono::{DateTime, Days, NaiveDate, NaiveDateTime};
+use chrono::{NaiveDate, NaiveDateTime};
 use std::mem;
 
 impl Serializer for NaiveDateTime {
-    fn fory_write_data(&self, context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
         let dt = self.and_utc();
         let micros = dt.timestamp() * 1_000_000 + dt.timestamp_subsec_micros() as i64;
         context.writer.write_i64(micros);
         Ok(())
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         let micros = context.reader.read_i64()?;
-        let seconds = micros / 1_000_000;
-        let subsec_micros = (micros % 1_000_000) as u32;
-        let nanos = subsec_micros * 1_000;
-        DateTime::from_timestamp(seconds, nanos)
-            .map(|dt| dt.naive_utc())
-            .ok_or(Error::InvalidData(
-                format!("Date out of range, timestamp micros: {micros}").into(),
-            ))
+        use chrono::TimeDelta;
+        let duration = TimeDelta::microseconds(micros);
+        #[allow(deprecated)]
+        let epoch_datetime = NaiveDateTime::from_timestamp(0, 0);
+        let result = epoch_datetime + duration;
+        Ok(result)
     }
 
     fn fory_reserved_space() -> usize {
@@ -58,33 +57,37 @@ impl Serializer for NaiveDateTime {
         Ok(TypeId::TIMESTAMP as u32)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        TypeId::TIMESTAMP
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_type_info::<Self>(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        context.writer.write_varuint32(TypeId::TIMESTAMP as u32);
+        Ok(())
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_type_info::<Self>(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_basic_type_info::<Self>(context)
     }
 }
 
 impl Serializer for NaiveDate {
-    fn fory_write_data(&self, context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
         let days_since_epoch = self.signed_duration_since(EPOCH).num_days();
         context.writer.write_i32(days_since_epoch as i32);
         Ok(())
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         let days = context.reader.read_i32()?;
-        EPOCH
-            .checked_add_days(Days::new(days as u64))
-            .ok_or(Error::InvalidData(
-                format!("Date out of range, {days} days since epoch").into(),
-            ))
+        use chrono::TimeDelta;
+        let duration = TimeDelta::days(days as i64);
+        let result = EPOCH + duration;
+        Ok(result)
     }
 
     fn fory_reserved_space() -> usize {
@@ -99,16 +102,21 @@ impl Serializer for NaiveDate {
         Ok(TypeId::LOCAL_DATE as u32)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        TypeId::LOCAL_DATE
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_type_info::<Self>(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        context.writer.write_varuint32(TypeId::LOCAL_DATE as u32);
+        Ok(())
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_type_info::<Self>(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_basic_type_info::<Self>(context)
     }
 }
 
diff --git a/rust/fory-core/src/serializer/enum_.rs b/rust/fory-core/src/serializer/enum_.rs
index 3cb323211..2d07ec109 100644
--- a/rust/fory-core/src/serializer/enum_.rs
+++ b/rust/fory-core/src/serializer/enum_.rs
@@ -17,7 +17,6 @@
 
 use crate::ensure;
 use crate::error::Error;
-use crate::meta::{MetaString, TypeMeta};
 use crate::resolver::context::{ReadContext, WriteContext};
 use crate::serializer::{ForyDefault, Serializer};
 use crate::types::{RefFlag, TypeId};
@@ -32,25 +31,23 @@ pub fn actual_type_id(type_id: u32, register_by_name: bool, _compatible: bool) -
 }
 
 #[inline(always)]
-pub fn type_def(
-    type_id: u32,
-    namespace: MetaString,
-    type_name: MetaString,
-    register_by_name: bool,
-) -> (Vec<u8>, TypeMeta) {
-    let meta = TypeMeta::from_fields(type_id, namespace, type_name, register_by_name, vec![]);
-    let bytes = meta.to_bytes().unwrap();
-    (bytes, meta)
-}
-
-#[inline(always)]
-pub fn write_type_info<T: Serializer>(
+pub fn write<T: Serializer>(
+    this: &T,
     context: &mut WriteContext,
-    is_field: bool,
+    write_ref_info: bool,
+    write_type_info: bool,
 ) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
+    if write_ref_info {
+        context.writer.write_i8(RefFlag::NotNullValue as i8);
     }
+    if write_type_info {
+        T::fory_write_type_info(context)?;
+    }
+    this.fory_write_data(context)
+}
+
+#[inline(always)]
+pub fn write_type_info<T: Serializer>(context: &mut WriteContext) -> Result<(), Error> {
     let type_id = T::fory_get_type_id(context.get_type_resolver())?;
     context.writer.write_varuint32(type_id);
     let is_named_enum = type_id & 0xff == TypeId::NAMED_ENUM as u32;
@@ -62,7 +59,7 @@ pub fn write_type_info<T: Serializer>(
         let meta_index = context.push_meta(rs_type_id)? as u32;
         context.writer.write_varuint32(meta_index);
     } else {
-        let type_info = context.get_type_resolver().get_type_info(rs_type_id)?;
+        let type_info = context.get_type_resolver().get_type_info(&rs_type_id)?;
         let namespace = type_info.get_namespace().to_owned();
         let type_name = type_info.get_type_name().to_owned();
         context.write_meta_string_bytes(&namespace)?;
@@ -72,18 +69,40 @@ pub fn write_type_info<T: Serializer>(
 }
 
 #[inline(always)]
-pub fn read_type_info<T: Serializer>(
+pub fn read<T: Serializer + ForyDefault>(
     context: &mut ReadContext,
-    is_field: bool,
-) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
+    read_ref_info: bool,
+    read_type_info: bool,
+) -> Result<T, Error> {
+    let ref_flag = if read_ref_info {
+        context.reader.read_i8()?
+    } else {
+        RefFlag::NotNullValue as i8
+    };
+    if ref_flag == RefFlag::Null as i8 {
+        Ok(T::fory_default())
+    } else if ref_flag == (RefFlag::NotNullValue as i8) || ref_flag == (RefFlag::RefValue as i8) {
+        if read_type_info {
+            T::fory_read_type_info(context)?;
+        }
+        T::fory_read_data(context)
+    } else if ref_flag == (RefFlag::Ref as i8) {
+        Err(Error::invalid_ref("Invalid ref, enum type is not a ref"))
+    } else {
+        Err(Error::invalid_data(format!(
+            "Unknown ref flag: {}",
+            ref_flag
+        )))
     }
+}
+
+#[inline(always)]
+pub fn read_type_info<T: Serializer>(context: &mut ReadContext) -> Result<(), Error> {
     let local_type_id = T::fory_get_type_id(context.get_type_resolver())?;
     let remote_type_id = context.reader.read_varuint32()?;
     ensure!(
         local_type_id == remote_type_id,
-        Error::TypeMismatch(local_type_id, remote_type_id)
+        Error::type_mismatch(local_type_id, remote_type_id)
     );
     let is_named_enum = local_type_id & 0xff == TypeId::NAMED_ENUM as u32;
     if !is_named_enum {
@@ -97,37 +116,3 @@ pub fn read_type_info<T: Serializer>(
     }
     Ok(())
 }
-
-#[inline(always)]
-pub fn read_compatible<T: Serializer + ForyDefault>(context: &mut ReadContext) -> Result<T, Error> {
-    T::fory_read_type_info(context, true)?;
-    T::fory_read_data(context, true)
-}
-
-#[inline(always)]
-pub fn write<T: Serializer>(
-    this: &T,
-
-    context: &mut WriteContext,
-    is_field: bool,
-) -> Result<(), Error> {
-    context.writer.write_i8(RefFlag::NotNullValue as i8);
-    T::fory_write_type_info(context, is_field)?;
-    this.fory_write_data(context, is_field)
-}
-
-#[inline(always)]
-pub fn read<T: Serializer + ForyDefault>(
-    context: &mut ReadContext,
-    is_field: bool,
-) -> Result<T, Error> {
-    let ref_flag = context.reader.read_i8()?;
-    if ref_flag == RefFlag::Null as i8 {
-        Ok(T::fory_default())
-    } else if ref_flag == (RefFlag::NotNullValue as i8) {
-        T::fory_read_type_info(context, false)?;
-        T::fory_read_data(context, is_field)
-    } else {
-        unimplemented!()
-    }
-}
diff --git a/rust/fory-core/src/serializer/heap.rs b/rust/fory-core/src/serializer/heap.rs
index 7c9af1871..f74b93997 100644
--- a/rust/fory-core/src/serializer/heap.rs
+++ b/rust/fory-core/src/serializer/heap.rs
@@ -20,7 +20,8 @@ use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
 use crate::serializer::collection::{
-    read_collection, read_collection_type_info, write_collection, write_collection_type_info,
+    read_collection_data, read_collection_type_info, write_collection_data,
+    write_collection_type_info,
 };
 
 use crate::serializer::{ForyDefault, Serializer};
@@ -29,20 +30,20 @@ use std::collections::BinaryHeap;
 use std::mem;
 
 impl<T: Serializer + ForyDefault + Ord> Serializer for BinaryHeap<T> {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection(self, context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_data(self, context, false)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection_type_info(context, is_field, TypeId::SET as u32)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_type_info(context, TypeId::SET as u32)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        read_collection(context)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        read_collection_data(context)
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_collection_type_info(context, is_field, TypeId::SET as u32)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_collection_type_info(context, TypeId::SET as u32)
     }
 
     fn fory_reserved_space() -> usize {
@@ -57,6 +58,10 @@ impl<T: Serializer + ForyDefault + Ord> Serializer for BinaryHeap<T> {
         Ok(TypeId::SET as u32)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        TypeId::SET
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
diff --git a/rust/fory-core/src/serializer/list.rs b/rust/fory-core/src/serializer/list.rs
index ba3a954af..b562e5323 100644
--- a/rust/fory-core/src/serializer/list.rs
+++ b/rust/fory-core/src/serializer/list.rs
@@ -27,7 +27,8 @@ use std::collections::{LinkedList, VecDeque};
 use std::mem;
 
 use super::collection::{
-    read_collection, read_collection_type_info, write_collection, write_collection_type_info,
+    read_collection_data, read_collection_type_info, write_collection_data,
+    write_collection_type_info,
 };
 
 fn check_primitive<T: 'static>() -> Option<TypeId> {
@@ -44,31 +45,42 @@ fn check_primitive<T: 'static>() -> Option<TypeId> {
 }
 
 impl<T: Serializer + ForyDefault> Serializer for Vec<T> {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
         match check_primitive::<T>() {
             Some(_) => primitive_list::fory_write_data(self, context),
-            None => write_collection(self, context, is_field),
+            None => write_collection_data(self, context, false),
         }
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
         match check_primitive::<T>() {
-            Some(type_id) => primitive_list::fory_write_type_info(context, is_field, type_id),
-            None => write_collection_type_info(context, is_field, TypeId::LIST as u32),
+            Some(_) => primitive_list::fory_write_data(self, context),
+            None => write_collection_data(self, context, has_generics),
+        }
+    }
+
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        match check_primitive::<T>() {
+            Some(type_id) => primitive_list::fory_write_type_info(context, type_id),
+            None => write_collection_type_info(context, TypeId::LIST as u32),
         }
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         match check_primitive::<T>() {
             Some(_) => primitive_list::fory_read_data(context),
-            None => read_collection(context),
+            None => read_collection_data(context),
         }
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
         match check_primitive::<T>() {
-            Some(type_id) => primitive_list::fory_read_type_info(context, is_field, type_id),
-            None => read_collection_type_info(context, is_field, TypeId::LIST as u32),
+            Some(type_id) => primitive_list::fory_read_type_info(context, type_id),
+            None => read_collection_type_info(context, TypeId::LIST as u32),
         }
     }
 
@@ -96,6 +108,16 @@ impl<T: Serializer + ForyDefault> Serializer for Vec<T> {
         })
     }
 
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        match check_primitive::<T>() {
+            Some(type_id) => type_id,
+            None => TypeId::LIST,
+        }
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
@@ -108,20 +130,28 @@ impl<T> ForyDefault for Vec<T> {
 }
 
 impl<T: Serializer + ForyDefault> Serializer for VecDeque<T> {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection(self, context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_data(self, context, false)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection_type_info(context, is_field, TypeId::LIST as u32)
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        write_collection_data(self, context, has_generics)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        read_collection(context)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_type_info(context, TypeId::LIST as u32)
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_collection_type_info(context, is_field, TypeId::LIST as u32)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        read_collection_data(context)
+    }
+
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_collection_type_info(context, TypeId::LIST as u32)
     }
 
     fn fory_reserved_space() -> usize {
@@ -136,6 +166,10 @@ impl<T: Serializer + ForyDefault> Serializer for VecDeque<T> {
         Ok(TypeId::LIST as u32)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        TypeId::LIST
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
@@ -148,20 +182,28 @@ impl<T> ForyDefault for VecDeque<T> {
 }
 
 impl<T: Serializer + ForyDefault> Serializer for LinkedList<T> {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection(self, context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_data(self, context, false)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection_type_info(context, is_field, TypeId::LIST as u32)
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        write_collection_data(self, context, has_generics)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        read_collection(context)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_type_info(context, TypeId::LIST as u32)
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_collection_type_info(context, is_field, TypeId::LIST as u32)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        read_collection_data(context)
+    }
+
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_collection_type_info(context, TypeId::LIST as u32)
     }
 
     fn fory_reserved_space() -> usize {
@@ -176,6 +218,10 @@ impl<T: Serializer + ForyDefault> Serializer for LinkedList<T> {
         Ok(TypeId::LIST as u32)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        TypeId::LIST
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
diff --git a/rust/fory-core/src/serializer/map.rs b/rust/fory-core/src/serializer/map.rs
index 526ef8927..37a075b8e 100644
--- a/rust/fory-core/src/serializer/map.rs
+++ b/rust/fory-core/src/serializer/map.rs
@@ -18,13 +18,12 @@
 use crate::ensure;
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
-use crate::serializer::{
-    read_ref_info_data, read_type_info, write_ref_info_data, write_type_info, ForyDefault,
-    Serializer,
-};
-use crate::types::{TypeId, SIZE_OF_REF_AND_TYPE};
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
+use crate::serializer::util::read_basic_type_info;
+use crate::serializer::{ForyDefault, Serializer};
+use crate::types::{need_to_write_type_for_field, TypeId, SIZE_OF_REF_AND_TYPE};
 use std::collections::{BTreeMap, HashMap};
+use std::sync::Arc;
 
 const MAX_CHUNK_SIZE: u8 = 255;
 
@@ -35,63 +34,19 @@ const TRACKING_VALUE_REF: u8 = 0b1000;
 pub const VALUE_NULL: u8 = 0b10000;
 const DECL_VALUE_TYPE: u8 = 0b100000;
 
-fn check_and_write_null<K: Serializer + Eq + std::hash::Hash, V: Serializer>(
-    context: &mut WriteContext,
-    is_field: bool,
-    key: &K,
-    value: &V,
-) -> Result<bool, Error> {
-    if key.fory_is_none() && value.fory_is_none() {
-        context.writer.write_u8(KEY_NULL | VALUE_NULL);
-        return Ok(true);
-    }
-    if key.fory_is_none() {
-        let mut chunk_header = KEY_NULL;
-        let skip_ref_flag;
-        if is_field {
-            skip_ref_flag = crate::serializer::get_skip_ref_flag::<V>(context.get_type_resolver())?;
-            chunk_header |= DECL_VALUE_TYPE;
-        } else {
-            skip_ref_flag = false;
-            chunk_header |= TRACKING_VALUE_REF;
-        }
-        context.writer.write_u8(chunk_header);
-
-        write_ref_info_data(value, context, is_field, skip_ref_flag, false)?;
-        return Ok(true);
-    }
-    if value.fory_is_none() {
-        let mut chunk_header = VALUE_NULL;
-        let skip_ref_flag;
-        if is_field {
-            // skip_ref_flag = crate::serializer::get_skip_ref_flag::<V>(context.get_fory());
-            skip_ref_flag = true;
-            chunk_header |= DECL_KEY_TYPE;
-        } else {
-            skip_ref_flag = false;
-            chunk_header |= TRACKING_KEY_REF;
-        }
-        context.writer.write_u8(chunk_header);
-        write_ref_info_data(key, context, is_field, skip_ref_flag, false)?;
-        return Ok(true);
-    }
-    Ok(false)
-}
-
 fn write_chunk_size(context: &mut WriteContext, header_offset: usize, size: u8) {
     context.writer.set_bytes(header_offset + 1, &[size]);
 }
 
-fn write_map_data<'a, K, V, I>(
+pub fn write_map_data<'a, K, V, I>(
     iter: I,
     length: usize,
-
     context: &mut WriteContext,
-    is_field: bool,
+    has_generics: bool,
 ) -> Result<(), Error>
 where
-    K: Serializer + ForyDefault + 'a + Eq + std::hash::Hash,
-    V: Serializer + ForyDefault + 'a,
+    K: Serializer,
+    V: Serializer,
     I: Iterator<Item = (&'a K, &'a V)>,
 {
     context.writer.write_varuint32(length as u32);
@@ -102,78 +57,495 @@ where
         + (V::fory_reserved_space() + SIZE_OF_REF_AND_TYPE) * length;
     context.writer.reserve(reserved_space);
 
+    if K::fory_is_polymorphic()
+        || K::fory_is_shared_ref()
+        || V::fory_is_polymorphic()
+        || V::fory_is_shared_ref()
+    {
+        return write_map_data_dyn_ref(iter, context, has_generics);
+    }
     let mut header_offset = 0;
     let mut pair_counter: u8 = 0;
     let mut need_write_header = true;
-    let mut skip_key_ref_flag = false;
-    let mut skip_val_ref_flag = false;
+    let key_static_type_id = K::fory_static_type_id();
+    let val_static_type_id = V::fory_static_type_id();
+    let is_key_declared = has_generics && !need_to_write_type_for_field(key_static_type_id);
+    let is_val_declared = has_generics && !need_to_write_type_for_field(val_static_type_id);
     for (key, value) in iter {
-        if need_write_header {
-            if check_and_write_null(context, is_field, key, value)? {
+        let key_is_none = key.fory_is_none();
+        let value_is_none = value.fory_is_none();
+
+        if key_is_none || value_is_none {
+            if !need_write_header && pair_counter > 0 {
+                write_chunk_size(context, header_offset, pair_counter);
+                pair_counter = 0;
+                need_write_header = true;
+            }
+
+            if key_is_none && value_is_none {
+                context.writer.write_u8(KEY_NULL | VALUE_NULL);
+                continue;
+            }
+
+            if value_is_none {
+                let mut chunk_header = VALUE_NULL;
+                if is_key_declared {
+                    chunk_header |= DECL_KEY_TYPE;
+                    context.writer.write_u8(chunk_header);
+                } else {
+                    context.writer.write_u8(chunk_header);
+                    K::fory_write_type_info(context)?;
+                }
+                key.fory_write_data_generic(context, has_generics)?;
                 continue;
             }
+
+            // key is None, value is not
+            let mut chunk_header = KEY_NULL;
+            if is_val_declared {
+                chunk_header |= DECL_VALUE_TYPE;
+                context.writer.write_u8(chunk_header);
+            } else {
+                context.writer.write_u8(chunk_header);
+                V::fory_write_type_info(context)?;
+            }
+            value.fory_write_data_generic(context, has_generics)?;
+            continue;
+        }
+
+        if need_write_header {
             header_offset = context.writer.len();
             context.writer.write_i16(-1);
-            let mut chunk_header = 0;
-            if is_field {
-                chunk_header |= DECL_KEY_TYPE | DECL_VALUE_TYPE;
+            let mut chunk_header = 0u8;
+            if is_key_declared {
+                chunk_header |= DECL_KEY_TYPE;
+            } else {
+                K::fory_write_type_info(context)?;
             }
-            skip_key_ref_flag = !K::fory_is_polymorphic();
-            skip_val_ref_flag = !V::fory_is_polymorphic();
-            if !skip_key_ref_flag {
-                chunk_header |= TRACKING_KEY_REF;
-            }
-            if !skip_val_ref_flag {
-                chunk_header |= TRACKING_VALUE_REF;
+            if is_val_declared {
+                chunk_header |= DECL_VALUE_TYPE;
+            } else {
+                V::fory_write_type_info(context)?;
             }
-            K::fory_write_type_info(context, is_field)?;
-            V::fory_write_type_info(context, is_field)?;
             context.writer.set_bytes(header_offset, &[chunk_header]);
             need_write_header = false;
         }
-        if key.fory_is_none() || value.fory_is_none() {
+
+        key.fory_write_data_generic(context, has_generics)?;
+        value.fory_write_data_generic(context, has_generics)?;
+        pair_counter += 1;
+        if pair_counter == MAX_CHUNK_SIZE {
             write_chunk_size(context, header_offset, pair_counter);
             pair_counter = 0;
             need_write_header = true;
-            check_and_write_null(context, is_field, key, value)?;
-            continue;
         }
-        if K::fory_is_polymorphic() || K::fory_is_shared_ref() {
-            key.fory_write(context, is_field)?;
+    }
+    if pair_counter > 0 {
+        write_chunk_size(context, header_offset, pair_counter);
+    }
+    Ok(())
+}
+
+/// slow but versatile map serialization for dynamic trait object and shared/circular reference.
+fn write_map_data_dyn_ref<'a, K, V, I>(
+    iter: I,
+    context: &mut WriteContext,
+    has_generics: bool,
+) -> Result<(), Error>
+where
+    K: Serializer,
+    V: Serializer,
+    I: Iterator<Item = (&'a K, &'a V)>,
+{
+    let mut header_offset = 0;
+    let mut pair_counter: u8 = 0;
+    let mut need_write_header = true;
+    let key_static_type_id = K::fory_static_type_id();
+    let val_static_type_id = V::fory_static_type_id();
+    let is_key_declared = has_generics && !need_to_write_type_for_field(key_static_type_id);
+    let is_val_declared = has_generics && !need_to_write_type_for_field(val_static_type_id);
+    let key_is_polymorphic = K::fory_is_polymorphic();
+    let val_is_polymorphic = V::fory_is_polymorphic();
+    let key_is_shared_ref = K::fory_is_shared_ref();
+    let val_is_shared_ref = V::fory_is_shared_ref();
+
+    // Track the current chunk's key and value types (for polymorphic types)
+    let mut current_key_type_id: Option<u32> = None;
+    let mut current_val_type_id: Option<u32> = None;
+
+    for (key, value) in iter {
+        // Handle null key/value entries (write as separate single-entry chunks)
+        if key.fory_is_none() || value.fory_is_none() {
+            // Finish current chunk if any
+            if pair_counter > 0 {
+                write_chunk_size(context, header_offset, pair_counter);
+                pair_counter = 0;
+                need_write_header = true;
+            }
+
+            if key.fory_is_none() && value.fory_is_none() {
+                context.writer.write_u8(KEY_NULL | VALUE_NULL);
+                continue;
+            } else if value.fory_is_none() {
+                let mut chunk_header = VALUE_NULL;
+                if key_is_shared_ref {
+                    chunk_header |= TRACKING_KEY_REF;
+                }
+                if is_key_declared && !key_is_polymorphic {
+                    chunk_header |= DECL_KEY_TYPE;
+                    context.writer.write_u8(chunk_header);
+                } else {
+                    context.writer.write_u8(chunk_header);
+                    if key_is_polymorphic {
+                        context.write_any_typeinfo(
+                            K::fory_static_type_id() as u32,
+                            key.fory_concrete_type_id(),
+                        )?;
+                    } else {
+                        K::fory_write_type_info(context)?;
+                    }
+                }
+                if key_is_shared_ref {
+                    key.fory_write(context, true, false, has_generics)?;
+                } else {
+                    key.fory_write_data_generic(context, has_generics)?;
+                }
+                continue;
+            } else {
+                // key.fory_is_none()
+                let mut chunk_header = KEY_NULL;
+                if val_is_shared_ref {
+                    chunk_header |= TRACKING_VALUE_REF;
+                }
+                if is_val_declared && !val_is_polymorphic {
+                    chunk_header |= DECL_VALUE_TYPE;
+                    context.writer.write_u8(chunk_header);
+                } else {
+                    context.writer.write_u8(chunk_header);
+                    if val_is_polymorphic {
+                        context.write_any_typeinfo(
+                            V::fory_static_type_id() as u32,
+                            value.fory_concrete_type_id(),
+                        )?;
+                    } else {
+                        V::fory_write_type_info(context)?;
+                    }
+                }
+                if val_is_shared_ref {
+                    value.fory_write(context, true, false, has_generics)?;
+                } else {
+                    value.fory_write_data_generic(context, has_generics)?;
+                }
+                continue;
+            }
+        }
+
+        // Get type IDs for polymorphic types
+        let key_type_id = if key_is_polymorphic {
+            Some(key.fory_type_id_dyn(context.get_type_resolver())?)
+        } else {
+            None
+        };
+        let val_type_id = if val_is_polymorphic {
+            Some(value.fory_type_id_dyn(context.get_type_resolver())?)
+        } else {
+            None
+        };
+
+        // Check if we need to start a new chunk due to type changes
+        let types_changed = if key_is_polymorphic || val_is_polymorphic {
+            key_type_id != current_key_type_id || val_type_id != current_val_type_id
         } else {
-            write_ref_info_data(key, context, is_field, skip_key_ref_flag, true)?;
+            false
+        };
+
+        if need_write_header || types_changed {
+            // Finish previous chunk if types changed
+            if types_changed && pair_counter > 0 {
+                write_chunk_size(context, header_offset, pair_counter);
+                pair_counter = 0;
+            }
+
+            // Write new chunk header
+            header_offset = context.writer.len();
+            context.writer.write_i16(-1); // Placeholder for header and size
+
+            let mut chunk_header = 0u8;
+
+            // Set key flags
+            if key_is_shared_ref {
+                chunk_header |= TRACKING_KEY_REF;
+            }
+            if is_key_declared && !key_is_polymorphic {
+                chunk_header |= DECL_KEY_TYPE;
+            } else {
+                // Write type info for key
+                if key_is_polymorphic {
+                    context.write_any_typeinfo(
+                        K::fory_static_type_id() as u32,
+                        key.fory_concrete_type_id(),
+                    )?;
+                } else {
+                    K::fory_write_type_info(context)?;
+                }
+            }
+
+            // Set value flags
+            if val_is_shared_ref {
+                chunk_header |= TRACKING_VALUE_REF;
+            }
+            if is_val_declared && !val_is_polymorphic {
+                chunk_header |= DECL_VALUE_TYPE;
+            } else {
+                // Write type info for value
+                if val_is_polymorphic {
+                    context.write_any_typeinfo(
+                        V::fory_static_type_id() as u32,
+                        value.fory_concrete_type_id(),
+                    )?;
+                } else {
+                    V::fory_write_type_info(context)?;
+                }
+            }
+
+            context.writer.set_bytes(header_offset, &[chunk_header]);
+            need_write_header = false;
+            current_key_type_id = key_type_id;
+            current_val_type_id = val_type_id;
+        }
+
+        // Write key-value pair
+        if key_is_shared_ref {
+            key.fory_write(context, true, false, has_generics)?;
+        } else {
+            key.fory_write_data_generic(context, has_generics)?;
         }
-        if V::fory_is_polymorphic() || V::fory_is_shared_ref() {
-            value.fory_write(context, is_field)?;
+        if val_is_shared_ref {
+            value.fory_write(context, true, false, has_generics)?;
         } else {
-            write_ref_info_data(value, context, is_field, skip_val_ref_flag, true)?;
+            value.fory_write_data_generic(context, has_generics)?;
         }
         pair_counter += 1;
         if pair_counter == MAX_CHUNK_SIZE {
             write_chunk_size(context, header_offset, pair_counter);
             pair_counter = 0;
             need_write_header = true;
+            current_key_type_id = None;
+            current_val_type_id = None;
         }
     }
+
+    // Write final chunk size if any
     if pair_counter > 0 {
         write_chunk_size(context, header_offset, pair_counter);
     }
+
     Ok(())
 }
 
+/// Macro to generate read_*_data_dyn_ref functions for HashMap and BTreeMap.
+/// This avoids code duplication while maintaining zero runtime cost.
+macro_rules! impl_read_map_dyn_ref {
+    ($fn_name:ident, $map_type:ty, $($extra_trait_bounds:tt)*) => {
+        fn $fn_name<K, V>(
+            context: &mut ReadContext,
+            mut map: $map_type,
+            length: u32,
+        ) -> Result<$map_type, Error>
+        where
+            K: Serializer + ForyDefault + $($extra_trait_bounds)*,
+            V: Serializer + ForyDefault,
+        {
+            let key_is_polymorphic = K::fory_is_polymorphic();
+            let val_is_polymorphic = V::fory_is_polymorphic();
+            let key_is_shared_ref = K::fory_is_shared_ref();
+            let val_is_shared_ref = V::fory_is_shared_ref();
+
+            let mut len_counter = 0u32;
+
+            while len_counter < length {
+                let header = context.reader.read_u8()?;
+
+                // Handle null key/value entries
+                if header & KEY_NULL != 0 && header & VALUE_NULL != 0 {
+                    // Both key and value are null
+                    map.insert(K::fory_default(), V::fory_default());
+                    len_counter += 1;
+                    continue;
+                }
+
+                if header & KEY_NULL != 0 {
+                    // Null key, non-null value
+                    let value_declared = (header & DECL_VALUE_TYPE) != 0;
+                    let track_value_ref = (header & TRACKING_VALUE_REF) != 0;
+
+                    // Determine value type info (if any)
+                    let value_type_info: Option<Arc<TypeInfo>> = if !value_declared {
+                        if val_is_polymorphic {
+                            Some(context.read_any_typeinfo()?)
+                        } else {
+                            V::fory_read_type_info(context)?;
+                            None
+                        }
+                    } else {
+                        None
+                    };
+
+                    // Read value payload
+                    let read_ref = val_is_shared_ref || track_value_ref;
+                    let value = if let Some(type_info) = value_type_info {
+                        V::fory_read_with_type_info(context, read_ref, type_info)?
+                    } else if read_ref {
+                        V::fory_read(context, read_ref, false)?
+                    } else {
+                        V::fory_read_data(context)?
+                    };
+
+                    map.insert(K::fory_default(), value);
+                    len_counter += 1;
+                    continue;
+                }
+
+                if header & VALUE_NULL != 0 {
+                    // Non-null key, null value
+                    let key_declared = (header & DECL_KEY_TYPE) != 0;
+                    let track_key_ref = (header & TRACKING_KEY_REF) != 0;
+
+                    let key_type_info: Option<Arc<TypeInfo>> = if !key_declared {
+                        if key_is_polymorphic {
+                            Some(context.read_any_typeinfo()?)
+                        } else {
+                            K::fory_read_type_info(context)?;
+                            None
+                        }
+                    } else {
+                        None
+                    };
+
+                    let read_ref = key_is_shared_ref || track_key_ref;
+                    let key = if let Some(type_info) = key_type_info {
+                        K::fory_read_with_type_info(context, read_ref, type_info)?
+                    } else if read_ref {
+                        K::fory_read(context, read_ref, false)?
+                    } else {
+                        K::fory_read_data(context)?
+                    };
+
+                    map.insert(key, V::fory_default());
+                    len_counter += 1;
+                    continue;
+                }
+
+                // Non-null key and value chunk
+                let chunk_size = context.reader.read_u8()?;
+                let key_declared = (header & DECL_KEY_TYPE) != 0;
+                let value_declared = (header & DECL_VALUE_TYPE) != 0;
+                let track_key_ref = (header & TRACKING_KEY_REF) != 0;
+                let track_value_ref = (header & TRACKING_VALUE_REF) != 0;
+
+                let key_type_info: Option<Arc<TypeInfo>> = if !key_declared {
+                    if key_is_polymorphic {
+                        Some(context.read_any_typeinfo()?)
+                    } else {
+                        K::fory_read_type_info(context)?;
+                        None
+                    }
+                } else {
+                    None
+                };
+                let value_type_info: Option<Arc<TypeInfo>> = if !value_declared {
+                    if val_is_polymorphic {
+                        Some(context.read_any_typeinfo()?)
+                    } else {
+                        V::fory_read_type_info(context)?;
+                        None
+                    }
+                } else {
+                    None
+                };
+
+                let cur_len = len_counter + chunk_size as u32;
+                ensure!(
+                    cur_len <= length,
+                    Error::invalid_data(
+                        format!("current length {} exceeds total length {}", cur_len, length)
+                    )
+                );
+
+                // Read chunk_size pairs of key-value
+                let key_read_ref = key_is_shared_ref || track_key_ref;
+                let val_read_ref = val_is_shared_ref || track_value_ref;
+                for _ in 0..chunk_size {
+                    let key = if let Some(type_info) = key_type_info.as_ref() {
+                        K::fory_read_with_type_info(context, key_read_ref, type_info.clone())?
+                    } else if key_read_ref {
+                        K::fory_read(context, key_read_ref, false)?
+                    } else {
+                        K::fory_read_data(context)?
+                    };
+
+                    let value = if let Some(type_info) = value_type_info.as_ref() {
+                        V::fory_read_with_type_info(context, val_read_ref, type_info.clone())?
+                    } else if val_read_ref {
+                        V::fory_read(context, val_read_ref, false)?
+                    } else {
+                        V::fory_read_data(context)?
+                    };
+
+                    map.insert(key, value);
+                }
+
+                len_counter += chunk_size as u32;
+            }
+
+            Ok(map)
+        }
+    };
+}
+
+// Generate read_hashmap_data_dyn_ref for HashMap
+impl_read_map_dyn_ref!(
+    read_hashmap_data_dyn_ref,
+    HashMap<K, V>,
+    Eq + std::hash::Hash
+);
+
+// Generate read_btreemap_data_dyn_ref for BTreeMap
+impl_read_map_dyn_ref!(
+    read_btreemap_data_dyn_ref,
+    BTreeMap<K, V>,
+    Ord
+);
+
 impl<K: Serializer + ForyDefault + Eq + std::hash::Hash, V: Serializer + ForyDefault> Serializer
     for HashMap<K, V>
 {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_map_data(self.iter(), self.len(), context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_map_data(self.iter(), self.len(), context, false)
+    }
+
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        write_map_data(self.iter(), self.len(), context, has_generics)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         let len = context.reader.read_varuint32()?;
         let mut map = HashMap::<K, V>::with_capacity(len as usize);
         if len == 0 {
             return Ok(map);
         }
+        if K::fory_is_polymorphic()
+            || K::fory_is_shared_ref()
+            || V::fory_is_polymorphic()
+            || V::fory_is_shared_ref()
+        {
+            let map: HashMap<K, V> = HashMap::with_capacity(len as usize);
+            return read_hashmap_data_dyn_ref(context, map, len);
+        }
         let mut len_counter = 0;
         loop {
             if len_counter == len {
@@ -188,52 +560,41 @@ impl<K: Serializer + ForyDefault + Eq + std::hash::Hash, V: Serializer + ForyDef
             let key_declared = (header & DECL_KEY_TYPE) != 0;
             let value_declared = (header & DECL_VALUE_TYPE) != 0;
             if header & KEY_NULL != 0 {
-                let skip_ref_flag = if value_declared {
-                    crate::serializer::get_skip_ref_flag::<V>(context.get_type_resolver())?
-                } else {
-                    false
-                };
-                let value = read_ref_info_data(context, value_declared, skip_ref_flag, false)?;
+                if !value_declared {
+                    V::fory_read_type_info(context)?;
+                }
+                let value = V::fory_read_data(context)?;
                 map.insert(K::fory_default(), value);
                 len_counter += 1;
                 continue;
             }
             if header & VALUE_NULL != 0 {
-                let skip_ref_flag = if key_declared {
-                    crate::serializer::get_skip_ref_flag::<K>(context.get_type_resolver())?
-                } else {
-                    false
-                };
-                let key = read_ref_info_data(context, key_declared, skip_ref_flag, false)?;
+                if !key_declared {
+                    K::fory_read_type_info(context)?;
+                }
+                let key = K::fory_read_data(context)?;
                 map.insert(key, V::fory_default());
                 len_counter += 1;
                 continue;
             }
             let chunk_size = context.reader.read_u8()?;
-            K::fory_read_type_info(context, key_declared)?;
-            V::fory_read_type_info(context, value_declared)?;
-
+            if header & DECL_KEY_TYPE == 0 {
+                K::fory_read_type_info(context)?;
+            }
+            if header & DECL_VALUE_TYPE == 0 {
+                V::fory_read_type_info(context)?;
+            }
             let cur_len = len_counter + chunk_size as u32;
             ensure!(
                 cur_len <= len,
-                Error::InvalidData(
-                    format!("current length {} exceeds total length {}", cur_len, len).into()
-                )
+                Error::invalid_data(format!(
+                    "current length {} exceeds total length {}",
+                    cur_len, len
+                ))
             );
-            assert!(len_counter + chunk_size as u32 <= len);
             for _ in 0..chunk_size {
-                let key = if K::fory_is_polymorphic() {
-                    K::fory_read(context, key_declared)?
-                } else {
-                    // let skip_ref_flag = crate::serializer::get_skip_ref_flag::<K>(context.get_fory());
-                    read_ref_info_data(context, key_declared, true, true)?
-                };
-                let value = if V::fory_is_polymorphic() {
-                    V::fory_read(context, value_declared)?
-                } else {
-                    // let skip_ref_flag = crate::serializer::get_skip_ref_flag::<V>(context.get_fory());
-                    read_ref_info_data(context, value_declared, true, true)?
-                };
+                let key = K::fory_read_data(context)?;
+                let value = V::fory_read_data(context)?;
                 map.insert(key, value);
             }
             len_counter += chunk_size as u32;
@@ -253,16 +614,24 @@ impl<K: Serializer + ForyDefault + Eq + std::hash::Hash, V: Serializer + ForyDef
         Ok(TypeId::MAP as u32)
     }
 
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        TypeId::MAP
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_type_info::<Self>(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        context.writer.write_varuint32(TypeId::MAP as u32);
+        Ok(())
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_type_info::<Self>(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_basic_type_info::<Self>(context)
     }
 }
 
@@ -275,16 +644,32 @@ impl<K, V> ForyDefault for HashMap<K, V> {
 impl<K: Serializer + ForyDefault + Ord + std::hash::Hash, V: Serializer + ForyDefault> Serializer
     for BTreeMap<K, V>
 {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_map_data(self.iter(), self.len(), context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_map_data(self.iter(), self.len(), context, false)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        write_map_data(self.iter(), self.len(), context, has_generics)
+    }
+
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         let len = context.reader.read_varuint32()?;
         let mut map = BTreeMap::<K, V>::new();
         if len == 0 {
             return Ok(map);
         }
+        if K::fory_is_polymorphic()
+            || K::fory_is_shared_ref()
+            || V::fory_is_polymorphic()
+            || V::fory_is_shared_ref()
+        {
+            let map: BTreeMap<K, V> = BTreeMap::new();
+            return read_btreemap_data_dyn_ref(context, map, len);
+        }
         let mut len_counter = 0;
         loop {
             if len_counter == len {
@@ -299,42 +684,41 @@ impl<K: Serializer + ForyDefault + Ord + std::hash::Hash, V: Serializer + ForyDe
             let key_declared = (header & DECL_KEY_TYPE) != 0;
             let value_declared = (header & DECL_VALUE_TYPE) != 0;
             if header & KEY_NULL != 0 {
-                let skip_ref_flag = if value_declared {
-                    crate::serializer::get_skip_ref_flag::<V>(context.get_type_resolver())?
-                } else {
-                    false
-                };
-                let value = read_ref_info_data(context, value_declared, skip_ref_flag, false)?;
+                if !value_declared {
+                    V::fory_read_type_info(context)?;
+                }
+                let value = V::fory_read_data(context)?;
                 map.insert(K::fory_default(), value);
                 len_counter += 1;
                 continue;
             }
             if header & VALUE_NULL != 0 {
-                let skip_ref_flag = if key_declared {
-                    crate::serializer::get_skip_ref_flag::<K>(context.get_type_resolver())?
-                } else {
-                    false
-                };
-                let key = read_ref_info_data(context, key_declared, skip_ref_flag, false)?;
+                if !key_declared {
+                    K::fory_read_type_info(context)?;
+                }
+                let key = K::fory_read_data(context)?;
                 map.insert(key, V::fory_default());
                 len_counter += 1;
                 continue;
             }
             let chunk_size = context.reader.read_u8()?;
-            K::fory_read_type_info(context, key_declared)?;
-            V::fory_read_type_info(context, value_declared)?;
-            assert!(len_counter + chunk_size as u32 <= len);
+            if header & DECL_KEY_TYPE == 0 {
+                K::fory_read_type_info(context)?;
+            }
+            if header & DECL_VALUE_TYPE == 0 {
+                V::fory_read_type_info(context)?;
+            }
+            let cur_len = len_counter + chunk_size as u32;
+            ensure!(
+                cur_len <= len,
+                Error::invalid_data(format!(
+                    "current length {} exceeds total length {}",
+                    cur_len, len
+                ))
+            );
             for _ in 0..chunk_size {
-                let key = if K::fory_is_polymorphic() {
-                    K::fory_read(context, key_declared)?
-                } else {
-                    read_ref_info_data(context, key_declared, true, true)?
-                };
-                let value = if V::fory_is_polymorphic() {
-                    V::fory_read(context, value_declared)?
-                } else {
-                    read_ref_info_data(context, value_declared, true, true)?
-                };
+                let key = K::fory_read_data(context)?;
+                let value = V::fory_read_data(context)?;
                 map.insert(key, value);
             }
             len_counter += chunk_size as u32;
@@ -354,16 +738,24 @@ impl<K: Serializer + ForyDefault + Ord + std::hash::Hash, V: Serializer + ForyDe
         Ok(TypeId::MAP as u32)
     }
 
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        TypeId::MAP
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_type_info::<Self>(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        context.writer.write_varuint32(TypeId::MAP as u32);
+        Ok(())
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_type_info::<Self>(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_basic_type_info::<Self>(context)
     }
 }
 
diff --git a/rust/fory-core/src/serializer/mod.rs b/rust/fory-core/src/serializer/mod.rs
index 4e1eca404..db2739089 100644
--- a/rust/fory-core/src/serializer/mod.rs
+++ b/rust/fory-core/src/serializer/mod.rs
@@ -15,13 +15,6 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use crate::error::Error;
-use crate::meta::{FieldInfo, NAMESPACE_DECODER, TYPE_NAME_DECODER};
-use crate::resolver::context::{ReadContext, WriteContext};
-use crate::types::{RefFlag, TypeId, PRIMITIVE_TYPES};
-use crate::{ensure, TypeResolver};
-use std::any::Any;
-
 pub mod any;
 mod arc;
 mod bool;
@@ -43,297 +36,9 @@ pub mod skip;
 mod string;
 pub mod struct_;
 pub mod trait_object;
+pub mod util;
 pub mod weak;
 
-#[inline(always)]
-pub fn write_ref_info_data<T: Serializer + 'static>(
-    record: &T,
-    context: &mut WriteContext,
-    is_field: bool,
-    skip_ref_flag: bool,
-    skip_type_info: bool,
-) -> Result<(), Error> {
-    if record.fory_is_none() {
-        context.writer.write_i8(RefFlag::Null as i8);
-    } else {
-        if !skip_ref_flag {
-            context.writer.write_i8(RefFlag::NotNullValue as i8);
-        }
-        if !skip_type_info {
-            T::fory_write_type_info(context, is_field)?;
-        }
-        record.fory_write_data(context, is_field)?;
-    }
-    Ok(())
-}
-
-#[inline(always)]
-pub fn read_ref_info_data<T: Serializer + ForyDefault>(
-    context: &mut ReadContext,
-    is_field: bool,
-    skip_ref_flag: bool,
-    skip_type_info: bool,
-) -> Result<T, Error> {
-    if !skip_ref_flag {
-        let ref_flag = context.reader.read_i8()?;
-        if ref_flag == RefFlag::Null as i8 {
-            Ok(T::fory_default())
-        } else if ref_flag == (RefFlag::NotNullValue as i8) {
-            if !skip_type_info {
-                T::fory_read_type_info(context, is_field)?;
-            }
-            T::fory_read_data(context, is_field)
-        } else if ref_flag == (RefFlag::RefValue as i8) {
-            // First time seeing this referenceable object
-            if !skip_type_info {
-                T::fory_read_type_info(context, is_field)?;
-            }
-            T::fory_read_data(context, is_field)
-        } else if ref_flag == (RefFlag::Ref as i8) {
-            // This is a reference to a previously deserialized object
-            // For now, just return default - this should be handled by specific types
-            Ok(T::fory_default())
-        } else {
-            unimplemented!("Unknown ref flag: {}", ref_flag)
-        }
-    } else {
-        if !skip_type_info {
-            T::fory_read_type_info(context, is_field)?;
-        }
-        T::fory_read_data(context, is_field)
-    }
-}
-
-#[inline(always)]
-pub fn write_type_info<T: Serializer>(
-    context: &mut WriteContext,
-    is_field: bool,
-) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
-    }
-    let type_id = T::fory_get_type_id(context.get_type_resolver())?;
-    context.writer.write_varuint32(type_id);
-    Ok(())
-}
-
-#[inline(always)]
-pub fn read_type_info<T: Serializer>(
-    context: &mut ReadContext,
-    is_field: bool,
-) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
-    }
-    let local_type_id = T::fory_get_type_id(context.get_type_resolver())?;
-    let remote_type_id = context.reader.read_varuint32()?;
-    ensure!(
-        local_type_id == remote_type_id,
-        Error::TypeMismatch(local_type_id, remote_type_id)
-    );
-    Ok(())
-}
-
-#[inline(always)]
-pub fn get_skip_ref_flag<T: Serializer>(type_resolver: &TypeResolver) -> Result<bool, Error> {
-    let elem_type_id = T::fory_get_type_id(type_resolver)?;
-    Ok(!T::fory_is_option() && PRIMITIVE_TYPES.contains(&elem_type_id))
-}
-
-pub trait ForyDefault: Sized {
-    fn fory_default() -> Self;
-}
-
-// We can't add blanket impl for all T: Default because it conflicts with other impls.
-// For example, upstream crates may add a new impl of trait `std::default::Default` for
-// type `std::rc::Rc<(dyn std::any::Any + 'static)>` in future versions.
-// impl<T: Default + Sized> ForyDefault for T {
-//     fn fory_default() -> Self {
-//         Default::default()
-//     }
-// }
-
-pub trait Serializer: 'static {
-    /// Entry point of the serialization.
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error>
-    where
-        Self: Sized,
-    {
-        write_ref_info_data(self, context, is_field, false, false)
-    }
-
-    fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self, Error>
-    where
-        Self: Sized + ForyDefault,
-    {
-        read_ref_info_data(context, is_field, false, false)
-    }
-
-    fn fory_is_option() -> bool
-    where
-        Self: Sized,
-    {
-        false
-    }
-
-    fn fory_is_none(&self) -> bool {
-        false
-    }
-
-    fn fory_is_polymorphic() -> bool
-    where
-        Self: Sized,
-    {
-        false
-    }
-
-    fn fory_is_shared_ref() -> bool
-    where
-        Self: Sized,
-    {
-        false
-    }
-
-    fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<u32, Error>
-    where
-        Self: Sized,
-    {
-        Ok(type_resolver
-            .get_type_info(std::any::TypeId::of::<Self>())?
-            .get_type_id())
-    }
-
-    fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32, Error>;
-
-    /// The possible max memory size of the type.
-    /// Used to reserve the buffer space to avoid reallocation, which may hurt performance.
-    fn fory_reserved_space() -> usize
-    where
-        Self: Sized,
-    {
-        0
-    }
-
-    fn fory_write_type_info(context: &mut WriteContext, _is_field: bool) -> Result<(), Error>
-    where
-        Self: Sized,
-    {
-        // default implementation only for ext/named_ext
-        let type_id = Self::fory_get_type_id(context.get_type_resolver())?;
-        context.writer.write_varuint32(type_id);
-        if type_id & 0xff == TypeId::EXT as u32 {
-            return Ok(());
-        }
-        let rs_type_id = std::any::TypeId::of::<Self>();
-        if context.is_share_meta() {
-            let meta_index = context.push_meta(rs_type_id)? as u32;
-            context.writer.write_varuint32(meta_index);
-        } else {
-            let type_info = context.get_type_resolver().get_type_info(rs_type_id)?;
-            let namespace = type_info.get_namespace().to_owned();
-            let type_name = type_info.get_type_name().to_owned();
-            context.write_meta_string_bytes(&namespace)?;
-            context.write_meta_string_bytes(&type_name)?;
-        }
-        Ok(())
-    }
-
-    fn fory_read_type_info(context: &mut ReadContext, _is_field: bool) -> Result<(), Error>
-    where
-        Self: Sized,
-    {
-        // default implementation only for ext/named_ext
-        let local_type_id = Self::fory_get_type_id(context.get_type_resolver())?;
-        let remote_type_id = context.reader.read_varuint32()?;
-        ensure!(
-            local_type_id == remote_type_id,
-            Error::TypeMismatch(local_type_id, remote_type_id)
-        );
-        if local_type_id & 0xff == TypeId::EXT as u32 {
-            return Ok(());
-        }
-        if context.is_share_meta() {
-            let _meta_index = context.reader.read_varuint32()?;
-        } else {
-            let _namespace_msb = context.read_meta_string_bytes()?;
-            let _type_name_msb = context.read_meta_string_bytes()?;
-        }
-        Ok(())
-    }
-
-    // only used by struct/enum/ext
-    fn fory_read_compatible(context: &mut ReadContext) -> Result<Self, Error>
-    where
-        Self: Sized,
-    {
-        // default logic only for ext/named_ext
-        let remote_type_id = context.reader.read_varuint32()?;
-        let local_type_id = Self::fory_get_type_id(context.get_type_resolver())?;
-        ensure!(
-            local_type_id == remote_type_id,
-            Error::TypeMismatch(local_type_id, remote_type_id)
-        );
-        if local_type_id & 0xff == TypeId::EXT as u32 {
-            context
-                .get_type_resolver()
-                .get_ext_harness(local_type_id)?
-                .get_read_data_fn()(context, true)
-            .and_then(|b: Box<dyn Any>| {
-                b.downcast::<Self>()
-                    .map(|boxed_self| *boxed_self)
-                    .map_err(|_| Error::TypeError("downcast to Self failed".into()))
-            })
-        } else {
-            let (namespace, type_name) = if context.is_share_meta() {
-                let meta_index = context.reader.read_varuint32()?;
-                let type_meta = context.get_meta(meta_index as usize);
-                (type_meta.get_namespace(), type_meta.get_type_name())
-            } else {
-                let nsb = context.read_meta_string_bytes()?;
-                let tsb = context.read_meta_string_bytes()?;
-                let ns = NAMESPACE_DECODER.decode(&nsb.bytes, nsb.encoding)?;
-                let ts = TYPE_NAME_DECODER.decode(&tsb.bytes, tsb.encoding)?;
-                (ns, ts)
-            };
-            context
-                .get_type_resolver()
-                .get_ext_name_harness(&namespace, &type_name)?
-                .get_read_data_fn()(context, true)
-            .and_then(|b: Box<dyn Any>| {
-                b.downcast::<Self>()
-                    .map(|boxed_self| *boxed_self)
-                    .map_err(|_| Error::TypeError("downcast to Self failed".into()))
-            })
-        }
-    }
-
-    /// Write/Read the data into the buffer. Need to be implemented.
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error>;
-
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error>
-    where
-        Self: Sized + ForyDefault;
-
-    fn fory_concrete_type_id(&self) -> std::any::TypeId {
-        std::any::TypeId::of::<Self>()
-    }
-
-    fn as_any(&self) -> &dyn Any;
-}
-
-pub trait StructSerializer: Serializer + 'static {
-    fn fory_fields_info(_: &TypeResolver) -> Result<Vec<FieldInfo>, Error> {
-        Ok(Vec::default())
-    }
-
-    fn fory_type_index() -> u32 {
-        unimplemented!()
-    }
-    fn fory_actual_type_id(type_id: u32, register_by_name: bool, compatible: bool) -> u32 {
-        struct_::actual_type_id(type_id, register_by_name, compatible)
-    }
-
-    fn fory_get_sorted_field_names() -> &'static [&'static str] {
-        &[]
-    }
-}
+mod core;
+pub use any::{read_box_any, write_box_any};
+pub use core::{ForyDefault, Serializer, StructSerializer};
diff --git a/rust/fory-core/src/serializer/mutex.rs b/rust/fory-core/src/serializer/mutex.rs
index b3bb0cb45..f6fcc3452 100644
--- a/rust/fory-core/src/serializer/mutex.rs
+++ b/rust/fory-core/src/serializer/mutex.rs
@@ -43,8 +43,10 @@
 //!   during serialization โ€” it is assumed this is a programmer error.
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 use crate::serializer::{ForyDefault, Serializer};
+use crate::types::TypeId;
+use std::sync::Arc;
 use std::sync::Mutex;
 
 /// `Serializer` impl for `Mutex<T>`
@@ -52,21 +54,41 @@ use std::sync::Mutex;
 /// Simply delegates to the serializer for `T`, allowing thread-safe interior mutable
 /// containers to be included in serialized graphs.
 impl<T: Serializer + ForyDefault> Serializer for Mutex<T> {
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_data: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
         // Don't add ref tracking for Mutex itself, just delegate to inner type
         // The inner type will handle its own ref tracking
         let guard = self.lock().unwrap();
-        T::fory_write(&*guard, context, is_field)
+        T::fory_write(
+            &*guard,
+            context,
+            write_ref_data,
+            write_type_info,
+            has_generics,
+        )
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        T::fory_write_data_generic(&*self.lock().unwrap(), context, has_generics)
+    }
+
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
         // When called from Rc/Arc, just delegate to inner type's data serialization
         let guard = self.lock().unwrap();
-        T::fory_write_data(&*guard, context, is_field)
+        T::fory_write_data(&*guard, context)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
     }
 
     fn fory_reserved_space() -> usize {
@@ -74,19 +96,42 @@ impl<T: Serializer + ForyDefault> Serializer for Mutex<T> {
         T::fory_reserved_space()
     }
 
-    fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self, Error>
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error>
     where
         Self: Sized + ForyDefault,
     {
-        Ok(Mutex::new(T::fory_read(context, is_field)?))
+        Ok(Mutex::new(T::fory_read(
+            context,
+            read_ref_info,
+            read_type_info,
+        )?))
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Ok(Mutex::new(T::fory_read_data(context, is_field)?))
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(Mutex::new(T::fory_read_with_type_info(
+            context,
+            read_ref_info,
+            type_info,
+        )?))
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        Ok(Mutex::new(T::fory_read_data(context)?))
+    }
+
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
     }
 
     fn fory_get_type_id(type_resolver: &TypeResolver) -> Result<u32, Error> {
@@ -98,6 +143,10 @@ impl<T: Serializer + ForyDefault> Serializer for Mutex<T> {
         (*guard).fory_type_id_dyn(type_resolver)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        T::fory_static_type_id()
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
diff --git a/rust/fory-core/src/serializer/number.rs b/rust/fory-core/src/serializer/number.rs
index c923bb15f..f5d53754d 100644
--- a/rust/fory-core/src/serializer/number.rs
+++ b/rust/fory-core/src/serializer/number.rs
@@ -20,25 +20,21 @@ use crate::error::Error;
 use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
-use crate::serializer::{read_type_info, write_type_info, ForyDefault, Serializer};
+use crate::serializer::util::read_basic_type_info;
+use crate::serializer::{ForyDefault, Serializer};
 use crate::types::TypeId;
 
 macro_rules! impl_num_serializer {
     ($ty:ty, $writer:expr, $reader:expr, $field_type:expr) => {
         impl Serializer for $ty {
             #[inline]
-            fn fory_write_data(
-                &self,
-
-                context: &mut WriteContext,
-                _is_field: bool,
-            ) -> Result<(), Error> {
+            fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
                 $writer(&mut context.writer, *self);
                 Ok(())
             }
 
             #[inline]
-            fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+            fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
                 $reader(&mut context.reader)
             }
 
@@ -56,22 +52,24 @@ macro_rules! impl_num_serializer {
                 Ok($field_type as u32)
             }
 
+            fn fory_static_type_id() -> TypeId {
+                $field_type
+            }
+
             #[inline]
             fn as_any(&self) -> &dyn std::any::Any {
                 self
             }
 
             #[inline]
-            fn fory_write_type_info(
-                context: &mut WriteContext,
-                is_field: bool,
-            ) -> Result<(), Error> {
-                write_type_info::<Self>(context, is_field)
+            fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+                context.writer.write_varuint32($field_type as u32);
+                Ok(())
             }
 
             #[inline]
-            fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-                read_type_info::<Self>(context, is_field)
+            fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+                read_basic_type_info::<Self>(context)
             }
         }
         impl ForyDefault for $ty {
diff --git a/rust/fory-core/src/serializer/option.rs b/rust/fory-core/src/serializer/option.rs
index 1a6dc0339..52c0dc138 100644
--- a/rust/fory-core/src/serializer/option.rs
+++ b/rust/fory-core/src/serializer/option.rs
@@ -20,30 +20,102 @@ use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
 use crate::serializer::{ForyDefault, Serializer};
+use crate::types::{RefFlag, TypeId};
 
 impl<T: Serializer + ForyDefault> Serializer for Option<T> {
     #[inline(always)]
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Ok(Some(T::fory_read_data(context, is_field)?))
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        if let Some(v) = self {
+            // pass has_generics to nested collection/map serializers
+            T::fory_write(v, context, write_ref_info, write_type_info, has_generics)
+        } else {
+            if write_ref_info {
+                context.writer.write_u8(RefFlag::Null as u8);
+            }
+            // no value, skip write type info
+            Ok(())
+        }
     }
 
     #[inline(always)]
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        if let Some(v) = self {
+            T::fory_write_data(v, context)
+        } else {
+            unreachable!("write should be call by serialize")
+        }
     }
 
     #[inline(always)]
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        if let Some(v) = self {
-            T::fory_write_data(v, context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
+    }
+
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        if read_ref_info {
+            let ref_flag = context.reader.read_i8()?;
+            if ref_flag == RefFlag::Null as i8 {
+                // null value won't write type info, so we can ignore `read_type_info`
+                return Ok(None);
+            }
+            if T::fory_is_shared_ref() {
+                // shared ref types always write ref flag, so we can ignore `read_type_info`
+                context.reader.move_back(1); // rewind to re-read ref flag in nested read
+                return Ok(Some(T::fory_read(context, true, read_type_info)?));
+            }
+        }
+        Ok(Some(T::fory_read(context, false, read_type_info)?))
+    }
+
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: std::sync::Arc<crate::TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        if read_ref_info {
+            let ref_flag = context.reader.read_i8()?;
+            if ref_flag == RefFlag::Null as i8 {
+                return Ok(None);
+            }
+        }
+        if T::fory_is_polymorphic() {
+            // Type info already resolved by caller
+            Ok(Some(T::fory_read_with_type_info(
+                context, false, type_info,
+            )?))
         } else {
-            unreachable!("write should be call by serialize")
+            Ok(Some(T::fory_read_data(context)?))
         }
     }
 
     #[inline(always)]
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        if T::fory_is_polymorphic() {
+            Ok(Some(T::fory_read(context, false, true)?))
+        } else {
+            Ok(Some(T::fory_read_data(context)?))
+        }
+    }
+
+    #[inline(always)]
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
     }
 
     #[inline(always)]
@@ -74,6 +146,11 @@ impl<T: Serializer + ForyDefault> Serializer for Option<T> {
         self.is_none()
     }
 
+    #[inline(always)]
+    fn fory_static_type_id() -> TypeId {
+        T::fory_static_type_id()
+    }
+
     #[inline(always)]
     fn as_any(&self) -> &dyn std::any::Any {
         self
diff --git a/rust/fory-core/src/serializer/primitive_list.rs b/rust/fory-core/src/serializer/primitive_list.rs
index 41b19161a..a8541e2e7 100644
--- a/rust/fory-core/src/serializer/primitive_list.rs
+++ b/rust/fory-core/src/serializer/primitive_list.rs
@@ -36,14 +36,7 @@ pub fn fory_write_data<T>(this: &[T], context: &mut WriteContext) -> Result<(),
     Ok(())
 }
 
-pub fn fory_write_type_info(
-    context: &mut WriteContext,
-    is_field: bool,
-    type_id: TypeId,
-) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
-    }
+pub fn fory_write_type_info(context: &mut WriteContext, type_id: TypeId) -> Result<(), Error> {
     context.writer.write_varuint32(type_id as u32);
     Ok(())
 }
@@ -51,7 +44,7 @@ pub fn fory_write_type_info(
 pub fn fory_read_data<T>(context: &mut ReadContext) -> Result<Vec<T>, Error> {
     let size_bytes = context.reader.read_varuint32()? as usize;
     if size_bytes % std::mem::size_of::<T>() != 0 {
-        return Err(Error::InvalidData("Invalid data length".into()));
+        return Err(Error::invalid_data("Invalid data length"));
     }
     let len = size_bytes / std::mem::size_of::<T>();
     let mut vec: Vec<T> = Vec::with_capacity(len);
@@ -64,27 +57,19 @@ pub fn fory_read_data<T>(context: &mut ReadContext) -> Result<Vec<T>, Error> {
     Ok(vec)
 }
 
-pub fn fory_read_type_info(
-    context: &mut ReadContext,
-    is_field: bool,
-    type_id: TypeId,
-) -> Result<(), Error> {
-    if is_field {
-        return Ok(());
-    }
+pub fn fory_read_type_info(context: &mut ReadContext, type_id: TypeId) -> Result<(), Error> {
     let remote_type_id = context.reader.read_varuint32()?;
     if remote_type_id == TypeId::LIST as u32 {
-        return Err(Error::TypeError(
+        return Err(Error::type_error(
             "Vec<number> belongs to the `number_array` type, \
                 and Vec<Option<number>> belongs to the `list` type. \
-                You should not read data of type `list` as data of type `number_array`."
-                .into(),
+                You should not read data of type `list` as data of type `number_array`.",
         ));
     }
     let local_type_id = type_id as u32;
     ensure!(
         local_type_id == remote_type_id,
-        Error::TypeMismatch(local_type_id, remote_type_id)
+        Error::type_mismatch(local_type_id, remote_type_id)
     );
     Ok(())
 }
diff --git a/rust/fory-core/src/serializer/rc.rs b/rust/fory-core/src/serializer/rc.rs
index c8750b4a9..7114e85bd 100644
--- a/rust/fory-core/src/serializer/rc.rs
+++ b/rust/fory-core/src/serializer/rc.rs
@@ -17,69 +17,86 @@
 
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 use crate::serializer::{ForyDefault, Serializer};
 use crate::types::RefFlag;
+use crate::types::TypeId;
 use std::rc::Rc;
+use std::sync::Arc;
 
 impl<T: Serializer + ForyDefault + 'static> Serializer for Rc<T> {
     fn fory_is_shared_ref() -> bool {
         true
     }
 
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        if !context
-            .ref_writer
-            .try_write_rc_ref(&mut context.writer, self)
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        if !write_ref_info
+            || !context
+                .ref_writer
+                .try_write_rc_ref(&mut context.writer, self)
         {
-            T::fory_write_data(self.as_ref(), context, is_field)?
-        };
-        Ok(())
+            if T::fory_is_shared_ref() || T::fory_is_polymorphic() {
+                let inner_write_ref = T::fory_is_shared_ref();
+                return T::fory_write(
+                    &**self,
+                    context,
+                    inner_write_ref,
+                    write_type_info,
+                    has_generics,
+                );
+            }
+            if write_type_info {
+                T::fory_write_type_info(context)?;
+            }
+            T::fory_write_data_generic(self, context, has_generics)
+        } else {
+            Ok(())
+        }
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        // When Rc is nested inside another shared ref (like Arc<Rc<T>>),
-        // the outer ref calls fory_write_data on the inner Rc.
-        // We still need to track the Rc's own references here.
-        self.fory_write(context, is_field)
+    fn fory_write_data_generic(&self, _: &mut WriteContext, _: bool) -> Result<(), Error> {
+        panic!("Rc<T> should be written using `fory_write` to handle reference tracking properly");
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_write_data(&self, _: &mut WriteContext) -> Result<(), Error> {
+        panic!("Rc<T> should be written using `fory_write` to handle reference tracking properly");
     }
 
-    fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
-        match ref_flag {
-            RefFlag::Null => Err(Error::InvalidRef("Rc cannot be null".into())),
-            RefFlag::Ref => {
-                let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
-                context.ref_reader.get_rc_ref::<T>(ref_id).ok_or_else(|| {
-                    Error::InvalidRef(format!("Rc reference {ref_id} not found").into())
-                })
-            }
-            RefFlag::NotNullValue => {
-                let inner = T::fory_read_data(context, is_field)?;
-                Ok(Rc::new(inner))
-            }
-            RefFlag::RefValue => {
-                let ref_id = context.ref_reader.reserve_ref_id();
-                let inner = T::fory_read_data(context, is_field)?;
-                let rc = Rc::new(inner);
-                context.ref_reader.store_rc_ref_at(ref_id, rc.clone());
-                Ok(rc)
-            }
-        }
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
+    }
+
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        read_rc(context, read_ref_info, read_type_info, None)
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        // When Rc is nested inside another shared ref, fory_read_data is called.
-        // Delegate to fory_read which handles ref tracking properly.
-        Self::fory_read(context, is_field)
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        typeinfo: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        read_rc(context, read_ref_info, false, Some(typeinfo))
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
+        panic!("Rc<T> should be read using `fory_read/fory_read_with_type_info` to handle reference tracking properly");
+    }
+
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
     }
 
     fn fory_reserved_space() -> usize {
@@ -96,11 +113,68 @@ impl<T: Serializer + ForyDefault + 'static> Serializer for Rc<T> {
         (**self).fory_type_id_dyn(type_resolver)
     }
 
+    fn fory_static_type_id() -> TypeId {
+        T::fory_static_type_id()
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 }
 
+fn read_rc<T: Serializer + ForyDefault + 'static>(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    typeinfo: Option<Arc<TypeInfo>>,
+) -> Result<Rc<T>, Error> {
+    let ref_flag = if read_ref_info {
+        context.ref_reader.read_ref_flag(&mut context.reader)?
+    } else {
+        RefFlag::NotNullValue
+    };
+    match ref_flag {
+        RefFlag::Null => Err(Error::invalid_ref("Rc cannot be null")),
+        RefFlag::Ref => {
+            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
+            context
+                .ref_reader
+                .get_rc_ref::<T>(ref_id)
+                .ok_or_else(|| Error::invalid_ref(format!("Rc reference {ref_id} not found")))
+        }
+        RefFlag::NotNullValue => {
+            let inner = read_rc_inner::<T>(context, read_type_info, typeinfo)?;
+            Ok(Rc::new(inner))
+        }
+        RefFlag::RefValue => {
+            let ref_id = context.ref_reader.reserve_ref_id();
+            let inner = read_rc_inner::<T>(context, read_type_info, typeinfo)?;
+            let rc = Rc::new(inner);
+            context.ref_reader.store_rc_ref_at(ref_id, rc.clone());
+            Ok(rc)
+        }
+    }
+}
+
+fn read_rc_inner<T: Serializer + ForyDefault + 'static>(
+    context: &mut ReadContext,
+    read_type_info: bool,
+    typeinfo: Option<Arc<TypeInfo>>,
+) -> Result<T, Error> {
+    if let Some(typeinfo) = typeinfo {
+        let inner_read_ref = T::fory_is_shared_ref();
+        return T::fory_read_with_type_info(context, inner_read_ref, typeinfo);
+    }
+    if T::fory_is_shared_ref() || T::fory_is_polymorphic() {
+        let inner_read_ref = T::fory_is_shared_ref();
+        return T::fory_read(context, inner_read_ref, read_type_info);
+    }
+    if read_type_info {
+        T::fory_read_type_info(context)?;
+    }
+    T::fory_read_data(context)
+}
+
 impl<T: ForyDefault> ForyDefault for Rc<T> {
     fn fory_default() -> Self {
         Rc::new(T::fory_default())
diff --git a/rust/fory-core/src/serializer/refcell.rs b/rust/fory-core/src/serializer/refcell.rs
index e1c194d8d..67d69cb2f 100644
--- a/rust/fory-core/src/serializer/refcell.rs
+++ b/rust/fory-core/src/serializer/refcell.rs
@@ -34,43 +34,87 @@
 //! ```
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 use crate::serializer::{ForyDefault, Serializer};
+use crate::types::TypeId;
 use std::cell::RefCell;
+use std::sync::Arc;
 
 /// `Serializer` impl for `RefCell<T>`
 ///
 /// Simply delegates to the serializer for `T`, allowing interior mutable
 /// containers to be included in serialized graphs.
 impl<T: Serializer + ForyDefault> Serializer for RefCell<T> {
-    fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self, Error>
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error>
     where
         Self: Sized + ForyDefault,
     {
-        Ok(RefCell::new(T::fory_read(context, is_field)?))
+        Ok(RefCell::new(T::fory_read(
+            context,
+            read_ref_info,
+            read_type_info,
+        )?))
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Ok(RefCell::new(T::fory_read_data(context, is_field)?))
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        Ok(RefCell::new(T::fory_read_with_type_info(
+            context,
+            read_ref_info,
+            type_info,
+        )?))
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        Ok(RefCell::new(T::fory_read_data(context)?))
     }
 
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
+    }
+
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
         // Don't add ref tracking for RefCell itself, just delegate to inner type
         // The inner type will handle its own ref tracking
-        T::fory_write(&*self.borrow(), context, is_field)
+        T::fory_write(
+            &*self.borrow(),
+            context,
+            write_ref_info,
+            write_type_info,
+            has_generics,
+        )
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        // When called from Rc, just delegate to inner type's data serialization
-        T::fory_write_data(&*self.borrow(), context, is_field)
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        T::fory_write_data_generic(&*self.borrow(), context, has_generics)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_data(&*self.borrow(), context)
+    }
+
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
     }
 
     fn fory_reserved_space() -> usize {
@@ -86,6 +130,13 @@ impl<T: Serializer + ForyDefault> Serializer for RefCell<T> {
         (*self.borrow()).fory_type_id_dyn(type_resolver)
     }
 
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        T::fory_static_type_id()
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
diff --git a/rust/fory-core/src/serializer/set.rs b/rust/fory-core/src/serializer/set.rs
index dd0bfaa0d..a317f0b36 100644
--- a/rust/fory-core/src/serializer/set.rs
+++ b/rust/fory-core/src/serializer/set.rs
@@ -20,7 +20,8 @@ use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
 use crate::serializer::collection::{
-    read_collection, read_collection_type_info, write_collection, write_collection_type_info,
+    read_collection_data, read_collection_type_info, write_collection_data,
+    write_collection_type_info,
 };
 
 use crate::serializer::{ForyDefault, Serializer};
@@ -29,20 +30,20 @@ use std::collections::{BTreeSet, HashSet};
 use std::mem;
 
 impl<T: Serializer + ForyDefault + Eq + std::hash::Hash> Serializer for HashSet<T> {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection(self, context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_data(self, context, false)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection_type_info(context, is_field, TypeId::SET as u32)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_type_info(context, TypeId::SET as u32)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        read_collection(context)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        read_collection_data(context)
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_collection_type_info(context, is_field, TypeId::SET as u32)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_collection_type_info(context, TypeId::SET as u32)
     }
 
     fn fory_reserved_space() -> usize {
@@ -57,6 +58,13 @@ impl<T: Serializer + ForyDefault + Eq + std::hash::Hash> Serializer for HashSet<
         Ok(TypeId::SET as u32)
     }
 
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        TypeId::SET
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
@@ -69,20 +77,20 @@ impl<T> ForyDefault for HashSet<T> {
 }
 
 impl<T: Serializer + ForyDefault + Ord> Serializer for BTreeSet<T> {
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection(self, context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_data(self, context, false)
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_collection_type_info(context, is_field, TypeId::SET as u32)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        write_collection_type_info(context, TypeId::SET as u32)
     }
 
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        read_collection(context)
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
+        read_collection_data(context)
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_collection_type_info(context, is_field, TypeId::SET as u32)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_collection_type_info(context, TypeId::SET as u32)
     }
 
     fn fory_reserved_space() -> usize {
@@ -97,6 +105,13 @@ impl<T: Serializer + ForyDefault + Ord> Serializer for BTreeSet<T> {
         Ok(TypeId::SET as u32)
     }
 
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        TypeId::SET
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
diff --git a/rust/fory-core/src/serializer/skip.rs b/rust/fory-core/src/serializer/skip.rs
index 8baf7eaaa..0b9cac214 100644
--- a/rust/fory-core/src/serializer/skip.rs
+++ b/rust/fory-core/src/serializer/skip.rs
@@ -20,21 +20,16 @@ use crate::error::Error;
 use crate::meta::FieldType;
 use crate::resolver::context::ReadContext;
 use crate::serializer::collection::{HAS_NULL, IS_SAME_TYPE};
+use crate::serializer::util;
 use crate::serializer::Serializer;
-use crate::types::{RefFlag, TypeId, BASIC_TYPES, CONTAINER_TYPES, PRIMITIVE_TYPES};
+use crate::types::{RefFlag, TypeId, BASIC_TYPES, CONTAINER_TYPES};
 use chrono::{NaiveDate, NaiveDateTime};
 
-pub fn get_read_ref_flag(field_type: &FieldType) -> bool {
-    let nullable = field_type.nullable;
-    nullable || !PRIMITIVE_TYPES.contains(&field_type.type_id)
-}
-
 macro_rules! basic_type_deserialize {
     ($tid:expr, $context:expr; $(($ty:ty, $id:ident)),+ $(,)?) => {
         $(
             if $tid == TypeId::$id {
-                <$ty as Serializer>::fory_read_type_info($context, true)?;
-                <$ty as Serializer>::fory_read_data($context, true)?;
+                <$ty as Serializer>::fory_read_data($context)?;
                 return Ok(());
             }
         )+else {
@@ -43,16 +38,26 @@ macro_rules! basic_type_deserialize {
     };
 }
 
-// call when is_field && is_compatible_mode
 #[allow(unreachable_code)]
 pub fn skip_field_value(
     context: &mut ReadContext,
     field_type: &FieldType,
     read_ref_flag: bool,
+) -> Result<(), Error> {
+    skip_value(context, field_type, read_ref_flag, true)
+}
+
+// call when is_field && is_compatible_mode
+#[allow(unreachable_code)]
+pub fn skip_value(
+    context: &mut ReadContext,
+    field_type: &FieldType,
+    read_ref_flag: bool,
+    _is_field: bool,
 ) -> Result<(), Error> {
     if read_ref_flag {
         let ref_flag = context.reader.read_i8()?;
-        if field_type.nullable && ref_flag == (RefFlag::Null as i8) {
+        if ref_flag == (RefFlag::Null as i8) {
             return Ok(());
         }
     }
@@ -92,7 +97,7 @@ pub fn skip_field_value(
                     let elem_type = field_type.generics.first().unwrap();
                     context.inc_depth()?;
                     for _ in 0..length {
-                        skip_field_value(context, elem_type, !skip_ref_flag)?;
+                        skip_value(context, elem_type, !skip_ref_flag, false)?;
                     }
                     context.dec_depth();
                 } else if type_id == TypeId::MAP {
@@ -115,17 +120,17 @@ pub fn skip_field_value(
                             continue;
                         }
                         if header & crate::serializer::map::KEY_NULL != 0 {
-                            // let read_ref_flag = get_read_ref_flag(value_type);
+                            // value_type.nullable determines whether ref flag was written
                             context.inc_depth()?;
-                            skip_field_value(context, value_type, false)?;
+                            skip_value(context, value_type, false, false)?;
                             context.dec_depth();
                             len_counter += 1;
                             continue;
                         }
                         if header & crate::serializer::map::VALUE_NULL != 0 {
-                            // let read_ref_flag = get_read_ref_flag(key_type);
+                            // key_type.nullable determines whether ref flag was written
                             context.inc_depth()?;
-                            skip_field_value(context, key_type, false)?;
+                            skip_value(context, key_type, false, false)?;
                             context.dec_depth();
                             len_counter += 1;
                             continue;
@@ -133,10 +138,10 @@ pub fn skip_field_value(
                         let chunk_size = context.reader.read_u8()?;
                         context.inc_depth()?;
                         for _ in (0..chunk_size).enumerate() {
-                            // let read_ref_flag = get_read_ref_flag(key_type);
-                            skip_field_value(context, key_type, false)?;
-                            // let read_ref_flag = get_read_ref_flag(value_type);
-                            skip_field_value(context, value_type, false)?;
+                            // key_type.nullable determines whether ref flag was written
+                            skip_value(context, key_type, false, false)?;
+                            // value_type.nullable determines whether ref flag was written
+                            skip_value(context, value_type, false, false)?;
                         }
                         context.dec_depth();
                         len_counter += chunk_size as u32;
@@ -150,15 +155,18 @@ pub fn skip_field_value(
                 let remote_type_id = context.reader.read_varuint32()?;
                 ensure!(
                     type_id_num == remote_type_id,
-                    Error::TypeMismatch(type_id_num, remote_type_id)
+                    Error::type_mismatch(type_id_num, remote_type_id)
                 );
                 let meta_index = context.reader.read_varuint32()?;
-                let type_meta = context.get_meta(meta_index as usize);
+                let type_meta = context.get_meta(meta_index as usize)?;
                 let field_infos = type_meta.get_field_infos().to_vec();
                 context.inc_depth()?;
                 for field_info in field_infos.iter() {
-                    let read_ref_flag = get_read_ref_flag(&field_info.field_type);
-                    skip_field_value(context, &field_info.field_type, read_ref_flag)?;
+                    let read_ref_flag = util::field_requires_ref_flag(
+                        field_info.field_type.type_id,
+                        field_info.field_type.nullable,
+                    );
+                    skip_value(context, &field_info.field_type, read_ref_flag, true)?;
                 }
                 context.dec_depth();
                 Ok(())
@@ -166,14 +174,14 @@ pub fn skip_field_value(
                 let remote_type_id = context.reader.read_varuint32()?;
                 ensure!(
                     type_id_num == remote_type_id,
-                    Error::TypeMismatch(type_id_num, remote_type_id)
+                    Error::type_mismatch(type_id_num, remote_type_id)
                 );
                 let meta_index = context.reader.read_varuint32()?;
-                let type_meta = context.get_meta(meta_index as usize);
+                let type_meta = context.get_meta(meta_index as usize)?;
                 let type_resolver = context.get_type_resolver();
                 type_resolver
                     .get_ext_name_harness(&type_meta.get_namespace(), &type_meta.get_type_name())?
-                    .get_read_data_fn()(context, true)?;
+                    .get_read_data_fn()(context)?;
                 Ok(())
             } else {
                 unreachable!("unimplemented type: {:?}", type_id);
@@ -187,34 +195,42 @@ pub fn skip_field_value(
             if internal_id == COMPATIBLE_STRUCT_ID {
                 let remote_type_id = context.reader.read_varuint32()?;
                 let meta_index = context.reader.read_varuint32()?;
-                let type_meta = context.get_meta(meta_index as usize);
+                let type_meta = context.get_meta(meta_index as usize)?;
                 ensure!(
                     type_meta.get_type_id() == remote_type_id,
-                    Error::TypeMismatch(type_meta.get_type_id(), remote_type_id)
+                    Error::type_mismatch(type_meta.get_type_id(), remote_type_id)
                 );
                 let field_infos = type_meta.get_field_infos().to_vec();
                 context.inc_depth()?;
                 for field_info in field_infos.iter() {
-                    let read_ref_flag = get_read_ref_flag(&field_info.field_type);
-                    skip_field_value(context, &field_info.field_type, read_ref_flag)?;
+                    let read_ref_flag = util::field_requires_ref_flag(
+                        field_info.field_type.type_id,
+                        field_info.field_type.nullable,
+                    );
+                    skip_value(context, &field_info.field_type, read_ref_flag, true)?;
                 }
                 context.dec_depth();
             } else if internal_id == ENUM_ID {
                 let _ordinal = context.reader.read_varuint32()?;
+                let _ordinalx = _ordinal;
+                println!("skip enum ordinal: {}", _ordinalx);
             } else if internal_id == EXT_ID {
                 let remote_type_id = context.reader.read_varuint32()?;
                 ensure!(
                     type_id_num == remote_type_id,
-                    Error::TypeMismatch(type_id_num, remote_type_id)
+                    Error::type_mismatch(type_id_num, remote_type_id)
                 );
                 context.inc_depth()?;
                 let type_resolver = context.get_type_resolver();
                 type_resolver
                     .get_ext_harness(type_id_num)?
-                    .get_read_data_fn()(context, true)?;
+                    .get_read_data_fn()(context)?;
                 context.dec_depth();
             } else {
-                unreachable!("unimplemented skipped type: {:?}", type_id_num);
+                return Err(Error::type_error(format!(
+                    "Unknown type id: {}",
+                    type_id_num
+                )));
             }
             Ok(())
         }
diff --git a/rust/fory-core/src/serializer/string.rs b/rust/fory-core/src/serializer/string.rs
index ad9b2c25c..d6b7c2fa6 100644
--- a/rust/fory-core/src/serializer/string.rs
+++ b/rust/fory-core/src/serializer/string.rs
@@ -20,7 +20,8 @@ use crate::meta::get_latin1_length;
 use crate::resolver::context::ReadContext;
 use crate::resolver::context::WriteContext;
 use crate::resolver::type_resolver::TypeResolver;
-use crate::serializer::{read_type_info, write_type_info, ForyDefault, Serializer};
+use crate::serializer::util::read_basic_type_info;
+use crate::serializer::{ForyDefault, Serializer};
 use crate::types::TypeId;
 use std::mem;
 
@@ -32,7 +33,7 @@ enum StrEncoding {
 
 impl Serializer for String {
     #[inline]
-    fn fory_write_data(&self, context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
         let mut len = get_latin1_length(self);
         if len >= 0 {
             let bitor = (len as u64) << 2 | StrEncoding::Latin1 as u64;
@@ -54,7 +55,7 @@ impl Serializer for String {
     }
 
     #[inline]
-    fn fory_read_data(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
+    fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
         let bitor = context.reader.read_varuint36small()?;
         let len = bitor >> 2;
         let encoding = bitor & 0b11;
@@ -63,9 +64,10 @@ impl Serializer for String {
             1 => StrEncoding::Utf16,
             2 => StrEncoding::Utf8,
             _ => {
-                return Err(Error::EncodingError(
-                    format!("wrong encoding value: {}", encoding).into(),
-                ))
+                return Err(Error::encoding_error(format!(
+                    "wrong encoding value: {}",
+                    encoding
+                )))
             }
         };
         let s = match encoding {
@@ -86,23 +88,33 @@ impl Serializer for String {
         Ok(TypeId::STRING as u32)
     }
 
+    #[inline(always)]
     fn fory_type_id_dyn(&self, _: &TypeResolver) -> Result<u32, Error> {
         Ok(TypeId::STRING as u32)
     }
 
+    #[inline(always)]
+    fn fory_static_type_id() -> TypeId
+    where
+        Self: Sized,
+    {
+        TypeId::STRING
+    }
+
     #[inline(always)]
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 
     #[inline(always)]
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        write_type_info::<Self>(context, is_field)
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        context.writer.write_varuint32(TypeId::STRING as u32);
+        Ok(())
     }
 
     #[inline(always)]
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        read_type_info::<Self>(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        read_basic_type_info::<Self>(context)
     }
 }
 
diff --git a/rust/fory-core/src/serializer/struct_.rs b/rust/fory-core/src/serializer/struct_.rs
index 5ec0137d6..98597e60b 100644
--- a/rust/fory-core/src/serializer/struct_.rs
+++ b/rust/fory-core/src/serializer/struct_.rs
@@ -20,6 +20,8 @@ use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
 use crate::serializer::Serializer;
 use crate::types::{RefFlag, TypeId};
+use std::any::Any;
+use std::sync::OnceLock;
 
 #[inline(always)]
 pub fn actual_type_id(type_id: u32, register_by_name: bool, compatible: bool) -> u32 {
@@ -37,10 +39,7 @@ pub fn actual_type_id(type_id: u32, register_by_name: bool, compatible: bool) ->
 }
 
 #[inline(always)]
-pub fn write_type_info<T: Serializer>(
-    context: &mut WriteContext,
-    _is_field: bool,
-) -> Result<(), Error> {
+pub fn write_type_info<T: Serializer>(context: &mut WriteContext) -> Result<(), Error> {
     let type_id = T::fory_get_type_id(context.get_type_resolver())?;
     context.writer.write_varuint32(type_id);
     let rs_type_id = std::any::TypeId::of::<T>();
@@ -50,7 +49,7 @@ pub fn write_type_info<T: Serializer>(
             let meta_index = context.push_meta(rs_type_id)? as u32;
             context.writer.write_varuint32(meta_index);
         } else {
-            let type_info = context.get_type_resolver().get_type_info(rs_type_id)?;
+            let type_info = context.get_type_resolver().get_type_info(&rs_type_id)?;
             let namespace = type_info.get_namespace().to_owned();
             let type_name = type_info.get_type_name().to_owned();
             context.write_meta_string_bytes(&namespace)?;
@@ -66,15 +65,12 @@ pub fn write_type_info<T: Serializer>(
 }
 
 #[inline(always)]
-pub fn read_type_info<T: Serializer>(
-    context: &mut ReadContext,
-    _is_field: bool,
-) -> Result<(), Error> {
+pub fn read_type_info<T: Serializer>(context: &mut ReadContext) -> Result<(), Error> {
     let remote_type_id = context.reader.read_varuint32()?;
     let local_type_id = T::fory_get_type_id(context.get_type_resolver())?;
     ensure!(
         local_type_id == remote_type_id,
-        Error::TypeMismatch(local_type_id, remote_type_id)
+        Error::type_mismatch(local_type_id, remote_type_id)
     );
 
     if local_type_id & 0xff == TypeId::NAMED_STRUCT as u32 {
@@ -96,17 +92,151 @@ pub fn read_type_info<T: Serializer>(
 pub fn write<T: Serializer>(
     this: &T,
     context: &mut WriteContext,
-    _is_field: bool,
+    write_ref_info: bool,
+    write_type_info: bool,
 ) -> Result<(), Error> {
-    if context.is_compatible() {
+    if write_ref_info {
         context.writer.write_i8(RefFlag::NotNullValue as i8);
-        T::fory_write_type_info(context, false)?;
-        this.fory_write_data(context, true)?;
-    } else {
-        // currently same
-        context.writer.write_i8(RefFlag::NotNullValue as i8);
-        T::fory_write_type_info(context, false)?;
-        this.fory_write_data(context, true)?;
     }
-    Ok(())
+    if write_type_info {
+        T::fory_write_type_info(context)?;
+    }
+    this.fory_write_data(context)
+}
+
+/// Global flag to check if ENABLE_FORY_DEBUG_OUTPUT environment variable is set.
+static ENABLE_FORY_DEBUG_OUTPUT: OnceLock<bool> = OnceLock::new();
+
+/// Check if ENABLE_FORY_DEBUG_OUTPUT environment variable is set.
+#[inline]
+fn enable_debug_output() -> bool {
+    *ENABLE_FORY_DEBUG_OUTPUT.get_or_init(|| {
+        std::env::var("ENABLE_FORY_DEBUG_OUTPUT")
+            .map(|v| v == "1" || v.eq_ignore_ascii_case("true"))
+            .unwrap_or(true)
+    })
+}
+
+pub type BeforeWriteFieldFunc =
+    fn(struct_name: &str, field_name: &str, field_value: &dyn Any, context: &mut WriteContext);
+pub type AfterWriteFieldFunc =
+    fn(struct_name: &str, field_name: &str, field_value: &dyn Any, context: &mut WriteContext);
+pub type BeforeReadFieldFunc = fn(struct_name: &str, field_name: &str, context: &mut ReadContext);
+pub type AfterReadFieldFunc =
+    fn(struct_name: &str, field_name: &str, field_value: &dyn Any, context: &mut ReadContext);
+
+fn default_before_write_field(
+    struct_name: &str,
+    field_name: &str,
+    _field_value: &dyn Any,
+    context: &mut WriteContext,
+) {
+    if enable_debug_output() {
+        println!(
+            "before_write_field:\tstruct={struct_name},\tfield={field_name},\twriter_len={}",
+            context.writer.len()
+        );
+    }
+}
+
+fn default_after_write_field(
+    struct_name: &str,
+    field_name: &str,
+    _field_value: &dyn Any,
+    context: &mut WriteContext,
+) {
+    if enable_debug_output() {
+        println!(
+            "after_write_field:\tstruct={struct_name},\tfield={field_name},\twriter_len={}",
+            context.writer.len()
+        );
+    }
+}
+
+fn default_before_read_field(struct_name: &str, field_name: &str, context: &mut ReadContext) {
+    if enable_debug_output() {
+        println!(
+            "before_read_field:\tstruct={struct_name},\tfield={field_name},\treader_cursor={}",
+            context.reader.get_cursor()
+        );
+    }
+}
+
+fn default_after_read_field(
+    struct_name: &str,
+    field_name: &str,
+    _field_value: &dyn Any,
+    context: &mut ReadContext,
+) {
+    if enable_debug_output() {
+        println!(
+            "after_read_field:\tstruct={struct_name},\tfield={field_name},\treader_cursor={}",
+            context.reader.get_cursor()
+        );
+    }
+}
+
+static mut BEFORE_WRITE_FIELD_FUNC: BeforeWriteFieldFunc = default_before_write_field;
+static mut AFTER_WRITE_FIELD_FUNC: AfterWriteFieldFunc = default_after_write_field;
+static mut BEFORE_READ_FIELD_FUNC: BeforeReadFieldFunc = default_before_read_field;
+static mut AFTER_READ_FIELD_FUNC: AfterReadFieldFunc = default_after_read_field;
+
+pub fn set_before_write_field_func(func: BeforeWriteFieldFunc) {
+    unsafe { BEFORE_WRITE_FIELD_FUNC = func }
+}
+
+pub fn set_after_write_field_func(func: AfterWriteFieldFunc) {
+    unsafe { AFTER_WRITE_FIELD_FUNC = func }
+}
+
+pub fn set_before_read_field_func(func: BeforeReadFieldFunc) {
+    unsafe { BEFORE_READ_FIELD_FUNC = func }
+}
+
+pub fn set_after_read_field_func(func: AfterReadFieldFunc) {
+    unsafe { AFTER_READ_FIELD_FUNC = func }
+}
+
+pub fn reset_struct_debug_hooks() {
+    unsafe {
+        BEFORE_WRITE_FIELD_FUNC = default_before_write_field;
+        AFTER_WRITE_FIELD_FUNC = default_after_write_field;
+        BEFORE_READ_FIELD_FUNC = default_before_read_field;
+        AFTER_READ_FIELD_FUNC = default_after_read_field;
+    }
+}
+
+/// Debug method to hook into struct serialization
+pub fn struct_before_write_field(
+    struct_name: &str,
+    field_name: &str,
+    field_value: &dyn Any,
+    context: &mut WriteContext,
+) {
+    unsafe { BEFORE_WRITE_FIELD_FUNC(struct_name, field_name, field_value, context) }
+}
+
+/// Debug method to hook into struct serialization
+pub fn struct_after_write_field(
+    struct_name: &str,
+    field_name: &str,
+    field_value: &dyn Any,
+    context: &mut WriteContext,
+) {
+    unsafe { AFTER_WRITE_FIELD_FUNC(struct_name, field_name, field_value, context) }
+}
+
+/// Debug method to hook into struct deserialization
+pub fn struct_before_read_field(struct_name: &str, field_name: &str, context: &mut ReadContext) {
+    unsafe { BEFORE_READ_FIELD_FUNC(struct_name, field_name, context) }
+}
+
+/// Debug method to hook into struct deserialization
+pub fn struct_after_read_field(
+    struct_name: &str,
+    field_name: &str,
+    field_value: &dyn Any,
+    context: &mut ReadContext,
+) {
+    unsafe { AFTER_READ_FIELD_FUNC(struct_name, field_name, field_value, context) }
 }
diff --git a/rust/fory-core/src/serializer/trait_object.rs b/rust/fory-core/src/serializer/trait_object.rs
index 7ee6daf92..97195b3ea 100644
--- a/rust/fory-core/src/serializer/trait_object.rs
+++ b/rust/fory-core/src/serializer/trait_object.rs
@@ -15,86 +15,47 @@
 // specific language governing permissions and limitations
 // under the License.
 
+// Re-exports for use in macros - these are needed for macro expansion in user crates
+// Even though they appear unused in this file, they are used by the macro-generated code
+
+use crate::ensure;
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 use crate::serializer::{ForyDefault, Serializer};
-
-/// Helper functions for trait object serialization to reduce code duplication
-///
-/// Writes common trait object headers (ref flag, type ID, compatibility metadata)
-pub fn write_trait_object_headers(
-    context: &mut WriteContext,
-    fory_type_id: u32,
-    concrete_type_id: std::any::TypeId,
-) -> Result<(), Error> {
-    use crate::types::{RefFlag, TypeId};
-
-    context.writer.write_i8(RefFlag::NotNullValue as i8);
-    context.writer.write_varuint32(fory_type_id);
-
-    if context.is_compatible()
-        && (fory_type_id & 0xff == TypeId::NAMED_COMPATIBLE_STRUCT as u32
-            || fory_type_id & 0xff == TypeId::COMPATIBLE_STRUCT as u32)
-    {
-        let meta_index = context.push_meta(concrete_type_id)? as u32;
-        context.writer.write_varuint32(meta_index);
-    };
-    Ok(())
-}
-
-/// Reads common trait object headers and returns the type ID
-pub fn read_trait_object_headers(context: &mut ReadContext) -> Result<u32, Error> {
-    use crate::types::{RefFlag, TypeId};
-
-    let ref_flag = context.reader.read_i8()?;
-    if ref_flag != RefFlag::NotNullValue as i8 {
-        return Err(Error::InvalidRef(
-            format!("Expected NotNullValue ref flag, got {ref_flag}").into(),
-        ));
-    }
-
-    let fory_type_id = context.reader.read_varuint32()?;
-
-    if context.is_compatible()
-        && (fory_type_id & 0xff == TypeId::NAMED_COMPATIBLE_STRUCT as u32
-            || fory_type_id & 0xff == TypeId::COMPATIBLE_STRUCT as u32)
-    {
-        let _meta_index = context.reader.read_varuint32()?;
-    }
-    Ok(fory_type_id)
-}
+use crate::RefFlag;
+use std::sync::Arc;
 
 /// Helper macro for common type resolution and downcasting pattern
 #[macro_export]
 macro_rules! downcast_and_serialize {
-    ($any_ref:expr, $context:expr, $is_field:expr, $trait_name:ident, $($impl_type:ty),+) => {{
+    ($any_ref:expr, $context:expr, $trait_name:ident, $($impl_type:ty),+) => {{
         $(
             if $any_ref.type_id() == std::any::TypeId::of::<$impl_type>() {
                 if let Some(concrete) = $any_ref.downcast_ref::<$impl_type>() {
-                    concrete.fory_write_data($context, $is_field)?;
+                    concrete.fory_write_data($context)?;
                     return Ok(());
                 }
             }
         )*
-        return Err($crate::error::Error::TypeError(format!("Failed to downcast to any registered type for trait {}", stringify!($trait_name)).into()));
+        return Err(fory_core::Error::type_error(format!("Failed to downcast to any registered type for trait {}", stringify!($trait_name))));
     }};
 }
 
 /// Helper macro for common type resolution and deserialization pattern
 #[macro_export]
 macro_rules! resolve_and_deserialize {
-    ($fory_type_id:expr, $context:expr, $is_field:expr, $constructor:expr, $trait_name:ident, $($impl_type:ty),+) => {{
+    ($fory_type_id:expr, $context:expr, $constructor:expr, $trait_name:ident, $($impl_type:ty),+) => {{
         $(
             if let Some(registered_type_id) = $context.get_type_resolver().get_fory_type_id(std::any::TypeId::of::<$impl_type>()) {
                 if $fory_type_id == registered_type_id {
-                    let concrete_obj = <$impl_type as $crate::serializer::Serializer>::fory_read_data($context, $is_field)?;
+                    let concrete_obj = <$impl_type as fory_core::Serializer>::fory_read_data($context)?;
                     return Ok($constructor(concrete_obj));
                 }
             }
         )*
-        Err($crate::error::Error::TypeError(
-            format!("Type ID {} not registered for trait {}", $fory_type_id, stringify!($trait_name)).into()
+        Err(fory_core::Error::type_error(
+            format!("Type ID {} not registered for trait {}", $fory_type_id, stringify!($trait_name))
         ))
     }};
 }
@@ -198,66 +159,91 @@ macro_rules! register_trait_type {
         );
 
         // 4. Serializer implementation for Box<dyn Trait> (existing functionality)
-        impl $crate::serializer::Serializer for Box<dyn $trait_name> {
-            fn fory_write(&self, context: &mut $crate::resolver::context::WriteContext, is_field: bool) -> Result<(), $crate::error::Error> {
-                let any_ref = <dyn $trait_name as $crate::serializer::Serializer>::as_any(&**self);
-                let concrete_type_id = any_ref.type_id();
+        impl fory_core::Serializer for Box<dyn $trait_name> {
+            fn fory_write(&self, context: &mut fory_core::WriteContext, write_ref_info: bool, write_type_info: bool, has_generics: bool) -> Result<(), fory_core::Error> {
+                let any_ref = <dyn $trait_name as fory_core::Serializer>::as_any(&**self);
+                fory_core::serializer::write_box_any(any_ref, context, write_ref_info, write_type_info, has_generics)
+            }
 
-                if let Some(fory_type_id) = context.get_type_resolver().get_fory_type_id(concrete_type_id) {
-                    $crate::serializer::trait_object::write_trait_object_headers(context, fory_type_id, concrete_type_id)?;
-                    $crate::downcast_and_serialize!(any_ref, context, is_field, $trait_name, $($impl_type),+);
-                } else {
-                    return Err($crate::error::Error::TypeError(format!("Type {:?} not registered for Box<dyn {}> serialization", concrete_type_id, stringify!($trait_name)).into()));
-                }
+            fn fory_write_data(&self, context: &mut fory_core::WriteContext) -> Result<(), fory_core::Error> {
+                let any_ref = <dyn $trait_name as fory_core::Serializer>::as_any(&**self);
+                fory_core::serializer::write_box_any(any_ref, context, false, false, false)
             }
 
-            fn fory_write_data(&self, context: &mut $crate::resolver::context::WriteContext, is_field: bool) -> Result<(), $crate::error::Error> {
-                // Delegate to fory_write since this handles the polymorphic dispatch
-                self.fory_write(context, is_field)
+            fn fory_write_data_generic(&self, context: &mut fory_core::WriteContext, has_generics: bool) -> Result<(), fory_core::Error> {
+                let any_ref = <dyn $trait_name as fory_core::Serializer>::as_any(&**self);
+                fory_core::serializer::write_box_any(any_ref, context, false, false, has_generics)
             }
 
-            fn fory_type_id_dyn(&self, type_resolver: &$crate::resolver::type_resolver::TypeResolver) -> Result<u32, $crate::error::Error> {
-                let any_ref = <dyn $trait_name as $crate::serializer::Serializer>::as_any(&**self);
+            fn fory_type_id_dyn(&self, type_resolver: &fory_core::TypeResolver) -> Result<u32, fory_core::Error> {
+                let any_ref = <dyn $trait_name as fory_core::Serializer>::as_any(&**self);
                 let concrete_type_id = any_ref.type_id();
                 type_resolver
                     .get_fory_type_id(concrete_type_id)
-                    .ok_or_else(|| $crate::error::Error::TypeError("Type not registered for trait object".into()))
+                    .ok_or_else(|| fory_core::Error::type_error("Type not registered for trait object"))
             }
 
             fn fory_is_polymorphic() -> bool {
                 true
             }
 
-            fn fory_write_type_info(_context: &mut $crate::resolver::context::WriteContext, _is_field: bool) -> Result<(), $crate::error::Error> {
-                // Box<dyn Trait> is polymorphic - type info is written per element
-                Ok(())
+            fn fory_write_type_info(_context: &mut fory_core::WriteContext) -> Result<(), fory_core::Error> {
+                $crate::not_allowed!("fory_write_type_info should not be called directly on polymorphic Box<dyn {}> trait object", stringify!($trait_name))
             }
 
-            fn fory_read_type_info(_context: &mut $crate::resolver::context::ReadContext, _is_field: bool) -> Result<(), $crate::error::Error> {
-                // Box<dyn Trait> is polymorphic - type info is read per element
-                Ok(())
+            fn fory_read_type_info(_context: &mut fory_core::ReadContext) -> Result<(), fory_core::Error> {
+                $crate::not_allowed!("fory_read_type_info should not be called directly on polymorphic Box<dyn {}> trait object", stringify!($trait_name))
             }
 
-            fn fory_read(context: &mut $crate::resolver::context::ReadContext, is_field: bool) -> Result<Self, $crate::error::Error> {
-                context.inc_depth()?;
-                let fory_type_id = $crate::serializer::trait_object::read_trait_object_headers(context)?;
-                let result = $crate::resolve_and_deserialize!(
-                    fory_type_id, context, is_field,
-                    |obj| Box::new(obj) as Box<dyn $trait_name>,
-                    $trait_name, $($impl_type),+
-                );
-                context.dec_depth();
-                result
+            fn fory_read(context: &mut fory_core::ReadContext, read_ref_info: bool, read_type_info: bool) -> Result<Self, fory_core::Error> {
+                let boxed_any = fory_core::serializer::read_box_any(context, read_ref_info, read_type_info, None)?;
+                $(
+                    if boxed_any.is::<$impl_type>() {
+                        let concrete = boxed_any.downcast::<$impl_type>()
+                            .map_err(|_| fory_core::Error::type_error("Downcast failed"))?;
+                        let ptr = Box::new(*concrete);
+                        return Ok(Self::from(ptr));
+                    }
+                )*
+                Err(fory_core::Error::type_error(
+                    format!("Deserialized type does not implement trait {}", stringify!($trait_name))
+                ))
+            }
+
+            fn fory_read_with_type_info(
+                context: &mut fory_core::ReadContext,
+                read_ref_info: bool,
+                type_info: std::sync::Arc<fory_core::TypeInfo>,
+            ) -> Result<Self, fory_core::Error>
+            where
+                Self: Sized + fory_core::ForyDefault,
+            {
+                let boxed_any = fory_core::serializer::read_box_any(context, read_ref_info, false, Some(type_info))?;
+                $(
+                    if boxed_any.is::<$impl_type>() {
+                        let concrete = boxed_any.downcast::<$impl_type>()
+                            .map_err(|_| fory_core::Error::type_error("Downcast failed"))?;
+                        let ptr = Box::new(*concrete);
+                        return Ok(Self::from(ptr));
+                    }
+                )*
+                Err(fory_core::Error::type_error(
+                    format!("Deserialized type does not implement trait {}", stringify!($trait_name))
+                ))
             }
 
-            fn fory_read_data(_context: &mut $crate::resolver::context::ReadContext, _is_field: bool) -> Result<Self, $crate::error::Error> {
+            fn fory_read_data(_context: &mut fory_core::ReadContext) -> Result<Self, fory_core::Error> {
                 // This should not be called for polymorphic types like Box<dyn Trait>
                 // The fory_read method handles the polymorphic dispatch
-                panic!("fory_read_data should not be called directly on polymorphic Box<dyn {}> trait object", stringify!($trait_name));
+                $crate::not_allowed!("fory_read_data should not be called directly on polymorphic Box<dyn {}> trait object", stringify!($trait_name))
+            }
+
+            fn fory_get_type_id(_type_resolver: &fory_core::TypeResolver) -> Result<u32, fory_core::Error> {
+                $crate::not_allowed!("fory_get_type_id should not be called directly on polymorphic Box<dyn {}> trait object", stringify!($trait_name))
             }
 
-            fn fory_get_type_id(_type_resolver: &$crate::resolver::type_resolver::TypeResolver) -> Result<u32, $crate::error::Error> {
-                Ok($crate::types::TypeId::STRUCT as u32)
+            fn fory_static_type_id() -> fory_core::TypeId {
+                fory_core::TypeId::UNKNOWN
             }
 
             fn fory_reserved_space() -> usize {
@@ -265,39 +251,11 @@ macro_rules! register_trait_type {
             }
 
             fn fory_concrete_type_id(&self) -> std::any::TypeId {
-                <dyn $trait_name as $crate::serializer::Serializer>::as_any(&**self).type_id()
+                <dyn $trait_name as fory_core::Serializer>::as_any(&**self).type_id()
             }
 
             fn as_any(&self) -> &dyn std::any::Any {
-                <dyn $trait_name as $crate::serializer::Serializer>::as_any(&**self)
-            }
-        }
-
-        // Create helper functions for this trait with trait-specific names
-        $crate::paste::paste! {
-            #[allow(non_snake_case)]
-            mod [<__fory_trait_helpers_ $trait_name>] {
-                use super::*;
-
-                #[allow(dead_code)]
-                pub fn [<from_any_internal_ $trait_name>](
-                    any_box: Box<dyn std::any::Any>,
-                    _fory_type_id: u32,
-                ) -> Result<Box<dyn $trait_name>, $crate::error::Error> {
-                    $(
-                        if any_box.is::<$impl_type>() {
-                            let concrete = any_box.downcast::<$impl_type>()
-                                .map_err(|_| $crate::error::Error::TypeError(
-                                    format!("Failed to downcast to {}", stringify!($impl_type)).into()
-                                ))?;
-                            return Ok(Box::new(*concrete) as Box<dyn $trait_name>);
-                        }
-                    )+
-
-                    Err($crate::error::Error::TypeError(
-                        format!("No matching type found for trait {}", stringify!($trait_name)).into()
-                    ))
-                }
+                <dyn $trait_name as fory_core::Serializer>::as_any(&**self)
             }
         }
     };
@@ -376,7 +334,7 @@ macro_rules! generate_smart_pointer_wrapper {
 
             impl std::fmt::Debug for [<$trait_name $ptr_name>] {
                 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                    let any_obj = <dyn $trait_name as $crate::serializer::Serializer>::as_any(&*self.0);
+                    let any_obj = <dyn $trait_name as fory_core::Serializer>::as_any(&*self.0);
                     $(
                         if let Some(concrete) = any_obj.downcast_ref::<$impl_type>() {
                             return write!(f, concat!(stringify!($trait_name), stringify!($ptr_name), "({:?})"), concrete);
@@ -400,108 +358,148 @@ macro_rules! generate_smart_pointer_wrapper {
     };
 }
 
+/// Macro to read smart pointer trait objects (Rc<dyn Trait>, Arc<dyn Trait>)
+/// This macro handles ref tracking and directly constructs the trait object from concrete types
+#[macro_export]
+macro_rules! read_ptr_trait_object {
+    ($context:expr, $read_ref_info:expr, $read_type_info:expr, $type_info:expr, $pointer_type:ty, $trait_name:ident, $constructor_expr:expr, $get_ref:ident, $store_ref:ident, $($impl_type:ty),+) => {{
+        let ref_flag = if $read_ref_info {
+            $context.ref_reader.read_ref_flag(&mut $context.reader)?
+        } else {
+            fory_core::RefFlag::NotNullValue
+        };
+        match ref_flag {
+            fory_core::RefFlag::Null => Err(fory_core::Error::invalid_ref(format!("smart pointer to dyn {} cannot be null", stringify!($trait_name)))),
+            fory_core::RefFlag::Ref => {
+                let ref_id = $context.ref_reader.read_ref_id(&mut $context.reader)?;
+                let ptr_ref = $context.ref_reader.$get_ref::<dyn $trait_name>(ref_id)
+                    .ok_or_else(|| fory_core::Error::invalid_data(format!("dyn {} reference {} not found", stringify!($trait_name), ref_id)))?;
+                Ok(Self::from(ptr_ref))
+            }
+            fory_core::RefFlag::NotNullValue => {
+                $context.inc_depth()?;
+                let typeinfo = if $read_type_info {
+                    $context.read_any_typeinfo()?
+                } else {
+                    $type_info.ok_or_else(|| fory_core::Error::type_error("No type info found for read"))?
+                };
+                let fory_type_id = typeinfo.get_type_id();
+                $(
+                    if let Some(registered_type_id) = $context.get_type_resolver().get_fory_type_id(std::any::TypeId::of::<$impl_type>()) {
+                        if fory_type_id == registered_type_id {
+                            let concrete_obj = <$impl_type as fory_core::Serializer>::fory_read_data($context)?;
+                            $context.dec_depth();
+                            let ptr = $constructor_expr(concrete_obj) as $pointer_type;
+                            return Ok(Self::from(ptr));
+                        }
+                    }
+                )*
+                $context.dec_depth();
+                Err(fory_core::Error::type_error(
+                    format!("Type ID {} not registered for trait {}", fory_type_id, stringify!($trait_name))
+                ))
+            }
+            fory_core::RefFlag::RefValue => {
+                $context.inc_depth()?;
+                let typeinfo = if $read_type_info {
+                    $context.read_any_typeinfo()?
+                } else {
+                    $type_info.ok_or_else(|| fory_core::Error::type_error("No type info found for read"))?
+                };
+                let fory_type_id = typeinfo.get_type_id();
+                $(
+                    if let Some(registered_type_id) = $context.get_type_resolver().get_fory_type_id(std::any::TypeId::of::<$impl_type>()) {
+                        if fory_type_id == registered_type_id {
+                            let concrete_obj = <$impl_type as fory_core::Serializer>::fory_read_data($context)?;
+                            $context.dec_depth();
+                            let ptr = $constructor_expr(concrete_obj) as $pointer_type;
+                            let wrapper = Self::from(ptr.clone());
+                            $context.ref_reader.$store_ref(ptr);
+                            return Ok(wrapper);
+                        }
+                    }
+                )*
+                $context.dec_depth();
+                Err(fory_core::Error::type_error(
+                    format!("Type ID {} not registered for trait {}", fory_type_id, stringify!($trait_name))
+                ))
+            }
+        }
+    }};
+}
+
 /// Shared serializer implementation for smart pointer wrappers
 #[macro_export]
 macro_rules! impl_smart_pointer_serializer {
     ($wrapper_name:ident, $pointer_type:ty, $constructor_expr:expr, $trait_name:ident, $try_write_ref:ident, $get_ref:ident, $store_ref:ident, $($impl_type:ty),+) => {
-        impl $crate::serializer::Serializer for $wrapper_name {
-            fn fory_write(&self, context: &mut $crate::resolver::context::WriteContext, is_field: bool) -> Result<(), $crate::error::Error> {
-                if !context.ref_writer.$try_write_ref(&mut context.writer, &self.0) {
-                    let any_obj = <dyn $trait_name as $crate::serializer::Serializer>::as_any(&*self.0);
+        impl fory_core::Serializer for $wrapper_name {
+            fn fory_write(&self, context: &mut fory_core::WriteContext, write_ref_info: bool, write_type_info: bool, has_generics: bool) -> Result<(), fory_core::Error> {
+                if !write_ref_info || !context.ref_writer.$try_write_ref(&mut context.writer, &self.0) {
+                    let any_obj = <dyn $trait_name as fory_core::Serializer>::as_any(&*self.0);
                     let concrete_type_id = any_obj.type_id();
-                    let harness = context.write_any_typeinfo(concrete_type_id)?;
-                    let serializer_fn = harness.get_write_data_fn();
-                    serializer_fn(any_obj, context, is_field)?;
+                    let typeinfo = if write_type_info {
+                         context.write_any_typeinfo(fory_core::TypeId::UNKNOWN as u32, concrete_type_id)?
+                    } else {
+                        context.get_type_info(&concrete_type_id)?
+                    };
+                    let serializer_fn = typeinfo.get_harness().get_write_data_fn();
+                    serializer_fn(any_obj, context, has_generics)?;
                 }
                 Ok(())
             }
 
-            fn fory_write_data(&self, context: &mut $crate::resolver::context::WriteContext, is_field: bool) -> Result<(), $crate::error::Error> {
-                let any_obj = <dyn $trait_name as $crate::serializer::Serializer>::as_any(&*self.0);
-                $crate::downcast_and_serialize!(any_obj, context, is_field, $trait_name, $($impl_type),+)
+            fn fory_write_data(&self, context: &mut fory_core::WriteContext) -> Result<(), fory_core::Error> {
+                let any_obj = <dyn $trait_name as fory_core::Serializer>::as_any(&*self.0);
+                $crate::downcast_and_serialize!(any_obj, context, $trait_name, $($impl_type),+)
             }
 
-            fn fory_read(context: &mut $crate::resolver::context::ReadContext, is_field: bool) -> Result<Self, $crate::error::Error> {
-                use $crate::types::RefFlag;
+            fn fory_read(context: &mut fory_core::ReadContext, read_ref_info: bool, read_type_info: bool) -> Result<Self, fory_core::Error> {
+                $crate::read_ptr_trait_object!(
+                    context,
+                    read_ref_info,
+                    read_type_info,
+                    None,
+                    $pointer_type,
+                    $trait_name,
+                    $constructor_expr,
+                    $get_ref,
+                    $store_ref,
+                    $($impl_type),+
+                )
+            }
 
-                let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
+            fn fory_read_with_type_info(context: &mut fory_core::ReadContext, read_ref_info: bool, type_info: std::sync::Arc<fory_core::TypeInfo>) -> Result<Self, fory_core::Error> {
+                $crate::read_ptr_trait_object!(
+                    context,
+                    read_ref_info,
+                    false,
+                    Some(type_info),
+                    $pointer_type,
+                    $trait_name,
+                    $constructor_expr,
+                    $get_ref,
+                    $store_ref,
+                    $($impl_type),+
+                )
+            }
 
-                match ref_flag {
-                    RefFlag::Null => Err($crate::error::Error::InvalidRef(
-                        format!("{}<dyn {}> cannot be null", stringify!($pointer_type), stringify!($trait_name)).into()
-                    )),
-                    RefFlag::Ref => {
-                        let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
-                        context.ref_reader.$get_ref::<dyn $trait_name>(ref_id)
-                            .map(|ptr| Self::from(ptr))
-                            .ok_or_else(|| $crate::error::Error::InvalidData(
-                                format!("{}<dyn {}> reference {} not found", stringify!($pointer_type), stringify!($trait_name), ref_id).into()
-                            ))
-                    }
-                    RefFlag::NotNullValue => {
-                        context.inc_depth()?;
-                        let harness = context.read_any_typeinfo()?;
-                        let deserializer_fn = harness.get_read_data_fn();
-                        let boxed_any = deserializer_fn(context, is_field)?;
-                        context.dec_depth();
-
-                        $(
-                            if boxed_any.is::<$impl_type>() {
-                                let concrete = boxed_any.downcast::<$impl_type>()
-                                    .map_err(|_| $crate::error::Error::TypeError("Downcast failed".into()))?;
-                                let ptr = $constructor_expr(*concrete) as $pointer_type;
-                                return Ok(Self::from(ptr));
-                            }
-                        )*
-
-                        Err($crate::error::Error::TypeError(
-                            format!("Deserialized type does not implement trait {}", stringify!($trait_name)).into()
-                        ))
-                    }
-                    RefFlag::RefValue => {
-                        context.inc_depth()?;
-                        let harness = context.read_any_typeinfo()?;
-                        let deserializer_fn = harness.get_read_data_fn();
-                        let boxed_any = deserializer_fn(context, is_field)?;
-                        context.dec_depth();
-
-                        $(
-                            if boxed_any.is::<$impl_type>() {
-                                let concrete = boxed_any.downcast::<$impl_type>()
-                                    .map_err(|_| $crate::error::Error::TypeError("Downcast failed".into()))?;
-                                let ptr = $constructor_expr(*concrete) as $pointer_type;
-                                context.ref_reader.$store_ref(ptr.clone());
-                                return Ok(Self::from(ptr));
-                            }
-                        )*
-
-                        Err($crate::error::Error::TypeError(
-                            format!("Deserialized type does not implement trait {}", stringify!($trait_name)).into()
-                        ))
-                    }
-                }
+            fn fory_read_data(context: &mut fory_core::ReadContext) -> Result<Self, fory_core::Error> {
+                $crate::not_allowed!("fory_read_data should not be called directly on polymorphic {}<dyn {}> trait object", stringify!($ptr_path), stringify!($trait_name))
             }
-            fn fory_read_data(context: &mut $crate::resolver::context::ReadContext, is_field: bool) -> Result<Self, $crate::error::Error> {
-                let concrete_fory_type_id = context.reader.read_varuint32()?;
-                $crate::resolve_and_deserialize!(
-                    concrete_fory_type_id, context, is_field,
-                    |obj| {
-                        let pointer = $constructor_expr(obj) as $pointer_type;
-                        Self::from(pointer)
-                    },
-                    $trait_name, $($impl_type),+
-                )
+
+            fn fory_get_type_id(_type_resolver: &fory_core::TypeResolver) -> Result<u32, fory_core::Error> {
+                Ok(fory_core::TypeId::STRUCT as u32)
             }
 
-            fn fory_get_type_id(_type_resolver: &$crate::resolver::type_resolver::TypeResolver) -> Result<u32, $crate::error::Error> {
-                Ok($crate::types::TypeId::STRUCT as u32)
+            fn fory_static_type_id() -> fory_core::TypeId {
+                fory_core::TypeId::UNKNOWN
             }
 
-            fn fory_write_type_info(_context: &mut $crate::resolver::context::WriteContext, _is_field: bool) -> Result<(), $crate::error::Error> {
+            fn fory_write_type_info(_context: &mut fory_core::WriteContext) -> Result<(), fory_core::Error> {
                 Ok(())
             }
 
-            fn fory_read_type_info(_context: &mut $crate::resolver::context::ReadContext, _is_field: bool) -> Result<(), $crate::error::Error>  {
+            fn fory_read_type_info(_context: &mut fory_core::ReadContext) -> Result<(), fory_core::Error>  {
                 Ok(())
             }
 
@@ -509,26 +507,70 @@ macro_rules! impl_smart_pointer_serializer {
                 true
             }
 
-            fn fory_type_id_dyn(&self, type_resolver: &$crate::resolver::type_resolver::TypeResolver) -> Result<u32, $crate::error::Error> {
-                let any_obj = <dyn $trait_name as $crate::serializer::Serializer>::as_any(&*self.0);
+            fn fory_is_shared_ref() -> bool {
+                true
+            }
+
+            fn fory_type_id_dyn(&self, type_resolver: &fory_core::TypeResolver) -> Result<u32, fory_core::Error> {
+                let any_obj = <dyn $trait_name as fory_core::Serializer>::as_any(&*self.0);
                 let concrete_type_id = any_obj.type_id();
                 type_resolver
                     .get_fory_type_id(concrete_type_id)
-                    .ok_or_else(|| $crate::error::Error::TypeError("Type not registered for trait object".into()))
+                    .ok_or_else(|| fory_core::Error::type_error("Type not registered for trait object"))
             }
 
             fn fory_concrete_type_id(&self) -> std::any::TypeId {
-                <dyn $trait_name as $crate::serializer::Serializer>::as_any(&*self.0).type_id()
+                <dyn $trait_name as fory_core::Serializer>::as_any(&*self.0).type_id()
             }
 
             fn as_any(&self) -> &dyn std::any::Any {
-                <dyn $trait_name as $crate::serializer::Serializer>::as_any(&*self.0)
+                <dyn $trait_name as fory_core::Serializer>::as_any(&*self.0)
             }
         }
     };
 }
 
-// Keep the existing Box<dyn Serializer> implementation as is
+/// Helper macros for automatic conversions in derive code
+/// These are used by fory-derive to generate transparent conversions
+///
+/// Convert field of type `Rc<dyn Trait>` to wrapper for serialization
+#[macro_export]
+macro_rules! wrap_rc {
+    ($field:expr, $trait_name:ident) => {
+        $crate::paste::paste! {
+            [<$trait_name Rc>]::from($field)
+        }
+    };
+}
+
+/// Convert wrapper back to `Rc<dyn Trait>` for deserialization
+#[macro_export]
+macro_rules! unwrap_rc {
+    ($wrapper:expr, $trait_name:ident) => {
+        std::rc::Rc::<dyn $trait_name>::from($wrapper)
+    };
+}
+
+/// Convert `Arc<dyn Trait>` to wrapper for serialization
+#[macro_export]
+macro_rules! wrap_arc {
+    ($field:expr, $trait_name:ident) => {
+        $crate::paste::paste! {
+            [<$trait_name Arc>]::from($field)
+        }
+    };
+}
+
+/// Convert `Vec<Rc<dyn Trait>>` to `Vec<wrapper>` for serialization
+#[macro_export]
+macro_rules! wrap_vec_rc {
+    ($vec:expr, $trait_name:ident) => {
+        $crate::paste::paste! {
+            $vec.into_iter().map(|item| [<$trait_name Rc>]::from(item)).collect()
+        }
+    };
+}
+
 impl Default for Box<dyn Serializer> {
     fn default() -> Self {
         Box::new(0)
@@ -542,16 +584,38 @@ impl ForyDefault for Box<dyn Serializer> {
 }
 
 impl Serializer for Box<dyn Serializer> {
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        let fory_type_id = (**self).fory_type_id_dyn(context.get_type_resolver())?;
+    fn fory_concrete_type_id(&self) -> std::any::TypeId {
+        (**self).fory_concrete_type_id()
+    }
+
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        if write_ref_info {
+            context.writer.write_i8(RefFlag::NotNullValue as i8);
+        }
+        let fory_type_id_dyn = self.fory_type_id_dyn(context.get_type_resolver())?;
         let concrete_type_id = (**self).fory_concrete_type_id();
+        if write_type_info {
+            context.write_any_typeinfo(fory_type_id_dyn, concrete_type_id)?;
+        };
+        self.fory_write_data_generic(context, has_generics)
+    }
 
-        write_trait_object_headers(context, fory_type_id, concrete_type_id)?;
-        (**self).fory_write_data(context, is_field)
+    fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
+        self.fory_write_data_generic(context, false)
     }
 
-    fn fory_write_data(&self, _context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
-        panic!("fory_write_data should not be called directly on Box<dyn Serializer>");
+    fn fory_write_data_generic(
+        &self,
+        context: &mut WriteContext,
+        has_generics: bool,
+    ) -> Result<(), Error> {
+        (**self).fory_write_data_generic(context, has_generics)
     }
 
     fn fory_type_id_dyn(&self, type_resolver: &TypeResolver) -> Result<u32, Error> {
@@ -566,98 +630,68 @@ impl Serializer for Box<dyn Serializer> {
         true
     }
 
-    fn fory_write_type_info(_context: &mut WriteContext, _is_field: bool) -> Result<(), Error> {
-        // Box<dyn Serializer> is polymorphic - type info is written per element
-        Ok(())
+    fn fory_write_type_info(_context: &mut WriteContext) -> Result<(), Error> {
+        panic!("Box<dyn Serializer> is polymorphic - can's write type info statically");
     }
 
-    fn fory_read_type_info(_context: &mut ReadContext, _is_field: bool) -> Result<(), Error> {
-        // Box<dyn Serializer> is polymorphic - type info is read per element
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        context.read_any_typeinfo()?;
         Ok(())
     }
 
-    fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        let fory_type_id = read_trait_object_headers(context)?;
-        context.inc_depth()?;
-        let type_resolver = context.get_type_resolver();
-
-        if let Some(harness) = type_resolver.get_harness(fory_type_id) {
-            let deserializer_fn = harness.get_read_fn();
-            let to_serializer_fn = harness.get_to_serializer();
-            let boxed_any = deserializer_fn(context, is_field, true)?;
-            let trait_object = to_serializer_fn(boxed_any)?;
-            context.dec_depth();
-            Ok(trait_object)
-        } else {
-            use crate::types::TypeId;
-            context.dec_depth();
-            match fory_type_id {
-                id if id == TypeId::LIST as u32 => {
-                    Err(Error::TypeError(format!(
-                        "Cannot deserialize LIST type ID {fory_type_id} as Box<dyn Serializer> without knowing concrete type. \
-                        Use concrete type instead (e.g., Vec<String>)"
-                    ).into()))
-                }
-                id if id == TypeId::MAP as u32 => {
-                    Err(Error::TypeError(format!(
-                        "Cannot deserialize MAP type ID {fory_type_id} as Box<dyn Serializer> without knowing concrete type. \
-                        Use concrete type instead (e.g., HashMap<String, i32>)"
-                    ).into()))
-                }
-                id if id == TypeId::SET as u32 => {
-                    Err(Error::TypeError(format!(
-                        "Cannot deserialize SET type ID {fory_type_id} as Box<dyn Serializer> without knowing concrete type. \
-                        Use concrete type instead (e.g., HashSet<i32>)"
-                    ).into()))
-                }
-                _ => {
-                    Err(Error::TypeError(format!("Type ID {fory_type_id} not registered").into()))
-                }
-            }
-        }
-    }
-    fn fory_read_data(_context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        panic!("fory_read_data should not be called directly on Box<dyn Serializer>");
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        read_box_seralizer(context, read_ref_info, read_type_info, None)
     }
-}
 
-/// Helper macros for automatic conversions in derive code
-/// These are used by fory-derive to generate transparent conversions
-///
-/// Convert field of type `Rc<dyn Trait>` to wrapper for serialization
-#[macro_export]
-macro_rules! wrap_rc {
-    ($field:expr, $trait_name:ident) => {
-        $crate::paste::paste! {
-            [<$trait_name Rc>]::from($field)
-        }
-    };
-}
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        type_info: Arc<TypeInfo>,
+    ) -> Result<Self, Error>
+    where
+        Self: Sized + ForyDefault,
+    {
+        read_box_seralizer(context, read_ref_info, false, Some(type_info))
+    }
 
-/// Convert wrapper back to `Rc<dyn Trait>` for deserialization
-#[macro_export]
-macro_rules! unwrap_rc {
-    ($wrapper:expr, $trait_name:ident) => {
-        std::rc::Rc::<dyn $trait_name>::from($wrapper)
-    };
+    fn fory_read_data(_context: &mut ReadContext) -> Result<Self, Error> {
+        panic!("fory_read_data should not be called directly on Box<dyn Serializer>");
+    }
 }
 
-/// Convert `Arc<dyn Trait>` to wrapper for serialization
-#[macro_export]
-macro_rules! wrap_arc {
-    ($field:expr, $trait_name:ident) => {
-        $crate::paste::paste! {
-            [<$trait_name Arc>]::from($field)
-        }
+fn read_box_seralizer(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    type_info: Option<Arc<TypeInfo>>,
+) -> Result<Box<dyn Serializer>, Error> {
+    context.inc_depth()?;
+    let ref_flag = if read_ref_info {
+        context.reader.read_i8()?
+    } else {
+        RefFlag::NotNullValue as i8
     };
-}
-
-/// Convert `Vec<Rc<dyn Trait>>` to `Vec<wrapper>` for serialization
-#[macro_export]
-macro_rules! wrap_vec_rc {
-    ($vec:expr, $trait_name:ident) => {
-        $crate::paste::paste! {
-            $vec.into_iter().map(|item| [<$trait_name Rc>]::from(item)).collect()
-        }
+    if ref_flag != RefFlag::NotNullValue as i8 {
+        return Err(Error::invalid_data(
+            "Expected NotNullValue for Box<dyn Serializer>",
+        ));
+    }
+    let typeinfo = if let Some(type_info) = type_info {
+        type_info
+    } else {
+        ensure!(
+            read_type_info,
+            Error::invalid_data("Type info must be read for Box<dyn Serializer>")
+        );
+        context.read_any_typeinfo()?
     };
+    let harness = typeinfo.get_harness();
+    let boxed_any = harness.get_read_data_fn()(context)?;
+    let trait_object = harness.get_to_serializer()(boxed_any)?;
+    context.dec_depth();
+    Ok(trait_object)
 }
diff --git a/rust/fory-core/src/serializer/util.rs b/rust/fory-core/src/serializer/util.rs
new file mode 100644
index 000000000..a344ce002
--- /dev/null
+++ b/rust/fory-core/src/serializer/util.rs
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+use crate::ensure;
+use crate::error::Error;
+use crate::resolver::context::{ReadContext, WriteContext};
+use crate::serializer::{bool, Serializer};
+use crate::types::TypeId;
+
+const NO_REF_FLAG_TYPE_IDS: [u32; 7] = [
+    TypeId::BOOL as u32,
+    TypeId::INT8 as u32,
+    TypeId::INT16 as u32,
+    TypeId::INT32 as u32,
+    TypeId::INT64 as u32,
+    TypeId::FLOAT32 as u32,
+    TypeId::FLOAT64 as u32,
+];
+
+#[inline(always)]
+pub(crate) fn read_basic_type_info<T: Serializer>(context: &mut ReadContext) -> Result<(), Error> {
+    let local_type_id = T::fory_get_type_id(context.get_type_resolver())?;
+    let remote_type_id = context.reader.read_varuint32()?;
+    ensure!(
+        local_type_id == remote_type_id,
+        Error::type_mismatch(local_type_id, remote_type_id)
+    );
+    Ok(())
+}
+
+/// Check at runtime whether type info should be skipped for a given type id.
+///
+/// According to xlang_serialization_spec.md:
+/// - For enums (ENUM/NAMED_ENUM), we should skip writing type info
+/// - For structs and ext types, we should write type info
+#[inline]
+pub fn should_skip_type_info_at_runtime(type_id: u32) -> bool {
+    let internal_type_id = (type_id & 0xff) as i8;
+    internal_type_id == TypeId::ENUM as i8 || internal_type_id == TypeId::NAMED_ENUM as i8
+}
+
+#[inline]
+pub fn field_requires_ref_flag(type_id: u32, nullable: bool) -> bool {
+    if nullable {
+        return true;
+    }
+    let internal_type_id = type_id & 0xff;
+    !NO_REF_FLAG_TYPE_IDS.contains(&internal_type_id)
+}
+
+#[inline(always)]
+pub fn write_dyn_data_generic<T: Serializer>(
+    value: &T,
+    context: &mut WriteContext,
+    has_generics: bool,
+) -> Result<(), Error> {
+    let any_value = value.as_any();
+    let concrete_type_id = any_value.type_id();
+    let serializer_fn = context
+        .write_any_typeinfo(T::fory_static_type_id() as u32, concrete_type_id)?
+        .get_harness()
+        .get_write_data_fn();
+    serializer_fn(any_value, context, has_generics)
+}
diff --git a/rust/fory-core/src/serializer/weak.rs b/rust/fory-core/src/serializer/weak.rs
index c04735901..d88f68a87 100644
--- a/rust/fory-core/src/serializer/weak.rs
+++ b/rust/fory-core/src/serializer/weak.rs
@@ -121,11 +121,13 @@
 //! - During deserialization, unresolved references will be patched up by `RefReader::add_callback`
 //!   once the strong pointer becomes available.
 
+use crate::ensure;
 use crate::error::Error;
 use crate::resolver::context::{ReadContext, WriteContext};
-use crate::resolver::type_resolver::TypeResolver;
+use crate::resolver::type_resolver::{TypeInfo, TypeResolver};
 use crate::serializer::{ForyDefault, Serializer};
 use crate::types::RefFlag;
+use crate::types::TypeId;
 use std::cell::UnsafeCell;
 use std::rc::Rc;
 use std::sync::Arc;
@@ -312,73 +314,70 @@ impl<T: Serializer + ForyDefault + 'static> Serializer for RcWeak<T> {
         true
     }
 
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
         if let Some(rc) = self.upgrade() {
-            if context
-                .ref_writer
-                .try_write_rc_ref(&mut context.writer, &rc)
+            if !write_ref_info
+                || !context
+                    .ref_writer
+                    .try_write_rc_ref(&mut context.writer, &rc)
             {
-                return Ok(());
+                if write_type_info {
+                    T::fory_write_type_info(context)?;
+                }
+                T::fory_write_data_generic(&*rc, context, has_generics)?;
             }
-            T::fory_write_data(&*rc, context, is_field)?;
         } else {
+            ensure!(write_ref_info, "Value pointed by RcWeak<T> is null");
+
             context.writer.write_i8(RefFlag::Null as i8);
         }
         Ok(())
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        self.fory_write(context, is_field)
+    fn fory_write_data_generic(&self, _: &mut WriteContext, _: bool) -> Result<(), Error> {
+        panic!(
+            "RcWeak<T> should be written using `fory_write` to handle reference tracking properly"
+        );
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_write_data(&self, _: &mut WriteContext) -> Result<(), Error> {
+        panic!(
+            "RcWeak<T> should be written using `fory_write` to handle reference tracking properly"
+        );
     }
 
-    fn fory_read(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
+    }
 
-        match ref_flag {
-            RefFlag::Null => Ok(RcWeak::new()),
-            RefFlag::RefValue => {
-                context.inc_depth()?;
-                let data = T::fory_read_data(context, is_field)?;
-                context.dec_depth();
-                let rc = Rc::new(data);
-                let ref_id = context.ref_reader.store_rc_ref(rc);
-                let rc = context.ref_reader.get_rc_ref::<T>(ref_id).unwrap();
-                Ok(RcWeak::from(&rc))
-            }
-            RefFlag::Ref => {
-                let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
-
-                if let Some(rc) = context.ref_reader.get_rc_ref::<T>(ref_id) {
-                    Ok(RcWeak::from(&rc))
-                } else {
-                    let result_weak = RcWeak::new();
-                    let callback_weak = result_weak.clone();
-
-                    context.ref_reader.add_callback(Box::new(move |ref_reader| {
-                        if let Some(rc) = ref_reader.get_rc_ref::<T>(ref_id) {
-                            callback_weak.update(Rc::downgrade(&rc));
-                        }
-                    }));
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        read_rc_weak::<T>(context, read_ref_info, read_type_info, None)
+    }
 
-                    Ok(result_weak)
-                }
-            }
-            _ => Err(Error::InvalidRef(
-                format!("Weak can only be Null, RefValue or Ref, got {:?}", ref_flag).into(),
-            )),
-        }
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        typeinfo: Arc<TypeInfo>,
+    ) -> Result<Self, Error> {
+        read_rc_weak::<T>(context, read_ref_info, false, Some(typeinfo))
     }
 
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Self::fory_read(context, is_field)
+    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
+        Err(Error::not_allowed("RcWeak<T> should be written using `fory_read/fory_read_with_type_info` to handle reference tracking properly"))
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
     }
 
     fn fory_reserved_space() -> usize {
@@ -398,11 +397,72 @@ impl<T: Serializer + ForyDefault + 'static> Serializer for RcWeak<T> {
         }
     }
 
+    fn fory_static_type_id() -> TypeId {
+        T::fory_static_type_id()
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 }
 
+fn read_rc_weak<T: Serializer + ForyDefault + 'static>(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    type_info: Option<Arc<TypeInfo>>,
+) -> Result<RcWeak<T>, Error> {
+    let ref_flag = if read_ref_info {
+        context.ref_reader.read_ref_flag(&mut context.reader)?
+    } else {
+        RefFlag::NotNullValue
+    };
+    match ref_flag {
+        RefFlag::Null => Ok(RcWeak::new()),
+        RefFlag::RefValue => {
+            context.inc_depth()?;
+            let data = if let Some(type_info) = type_info {
+                T::fory_read_with_type_info(context, false, type_info)?
+            } else {
+                if read_type_info {
+                    context.read_any_typeinfo()?;
+                }
+                T::fory_read_data(context)?
+            };
+            context.dec_depth();
+            let rc = Rc::new(data);
+            let ref_id = context.ref_reader.store_rc_ref(rc);
+            let rc = context.ref_reader.get_rc_ref::<T>(ref_id).unwrap();
+            Ok(RcWeak::from(&rc))
+        }
+        RefFlag::Ref => {
+            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
+            if let Some(rc) = context.ref_reader.get_rc_ref::<T>(ref_id) {
+                Ok(RcWeak::from(&rc))
+            } else {
+                let result_weak = RcWeak::new();
+                let callback_weak = result_weak.clone();
+                context.ref_reader.add_callback(Box::new(move |ref_reader| {
+                    if let Some(rc) = ref_reader.get_rc_ref::<T>(ref_id) {
+                        callback_weak.update(Rc::downgrade(&rc));
+                    }
+                }));
+
+                Ok(result_weak)
+            }
+        }
+        RefFlag::NotNullValue => {
+            // let inner = if let Some(typeinfo) = type_info {
+            //     T::fory_read_with_type_info(context, false, typeinfo)?
+            // } else {
+            //     T::fory_read_data(context)?
+            // };
+            // Ok(RcWeak::from(&Rc::new(inner)))
+            Err(Error::invalid_ref("RcWeak can't hold a strong ref value"))
+        }
+    }
+}
+
 impl<T: ForyDefault> ForyDefault for RcWeak<T> {
     fn fory_default() -> Self {
         RcWeak::new()
@@ -414,77 +474,69 @@ impl<T: Serializer + ForyDefault + Send + Sync + 'static> Serializer for ArcWeak
         true
     }
 
-    fn fory_write(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+    fn fory_write(
+        &self,
+        context: &mut WriteContext,
+        write_ref_info: bool,
+        write_type_info: bool,
+        has_generics: bool,
+    ) -> Result<(), Error> {
         if let Some(arc) = self.upgrade() {
-            // IMPORTANT: If the target Arc was serialized already, just write a ref
-            if context
-                .ref_writer
-                .try_write_arc_ref(&mut context.writer, &arc)
+            if !write_ref_info
+                || !context
+                    .ref_writer
+                    .try_write_arc_ref(&mut context.writer, &arc)
             {
-                // Already seen, wrote Ref flag + id, we're done
-                return Ok(());
+                if write_type_info {
+                    T::fory_write_type_info(context)?;
+                }
+                T::fory_write_data_generic(&*arc, context, has_generics)?;
             }
-            // First time seeing this object, write RefValue and then its data
-            T::fory_write_data(&*arc, context, is_field)?;
         } else {
+            ensure!(write_ref_info, "Value pointed by ArcWeak<T> is null");
             context.writer.write_i8(RefFlag::Null as i8);
         }
         Ok(())
     }
 
-    fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        self.fory_write(context, is_field)
+    fn fory_write_data_generic(&self, _: &mut WriteContext, _: bool) -> Result<(), Error> {
+        panic!(
+            "ArcWeak<T> should be written using `fory_write` to handle reference tracking properly"
+        );
     }
 
-    fn fory_write_type_info(context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
-        T::fory_write_type_info(context, is_field)
+    fn fory_write_data(&self, _: &mut WriteContext) -> Result<(), Error> {
+        panic!(
+            "ArcWeak<T> should be written using `fory_write` to handle reference tracking properly"
+        );
     }
 
-    fn fory_read(context: &mut ReadContext, _is_field: bool) -> Result<Self, Error> {
-        let ref_flag = context.ref_reader.read_ref_flag(&mut context.reader)?;
+    fn fory_write_type_info(context: &mut WriteContext) -> Result<(), Error> {
+        T::fory_write_type_info(context)
+    }
 
-        match ref_flag {
-            RefFlag::Null => Ok(ArcWeak::new()),
-            RefFlag::RefValue => {
-                context.inc_depth()?;
-                let data = T::fory_read_data(context, _is_field)?;
-                context.dec_depth();
-                let arc = Arc::new(data);
-                let ref_id = context.ref_reader.store_arc_ref(arc);
-                let arc = context.ref_reader.get_arc_ref::<T>(ref_id).unwrap();
-                let weak = ArcWeak::from(&arc);
-                Ok(weak)
-            }
-            RefFlag::Ref => {
-                let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
-                let weak = ArcWeak::new();
-
-                if let Some(arc) = context.ref_reader.get_arc_ref::<T>(ref_id) {
-                    weak.update(Arc::downgrade(&arc));
-                } else {
-                    // Capture the raw pointer to the UnsafeCell so we can update it in the callback
-                    let weak_ptr = weak.inner.get();
-                    context.ref_reader.add_callback(Box::new(move |ref_reader| {
-                        if let Some(arc) = ref_reader.get_arc_ref::<T>(ref_id) {
-                            unsafe {
-                                *weak_ptr = Arc::downgrade(&arc);
-                            }
-                        }
-                    }));
-                }
-                Ok(weak)
-            }
-            _ => Err(Error::InvalidRef(
-                format!("Weak can only be Null, RefValue or Ref, got {:?}", ref_flag).into(),
-            )),
-        }
+    fn fory_read(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        read_type_info: bool,
+    ) -> Result<Self, Error> {
+        read_arc_weak(context, read_ref_info, read_type_info, None)
     }
-    fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
-        Self::fory_read(context, is_field)
+
+    fn fory_read_with_type_info(
+        context: &mut ReadContext,
+        read_ref_info: bool,
+        typeinfo: Arc<TypeInfo>,
+    ) -> Result<Self, Error> {
+        read_arc_weak::<T>(context, read_ref_info, false, Some(typeinfo))
     }
 
-    fn fory_read_type_info(context: &mut ReadContext, is_field: bool) -> Result<(), Error> {
-        T::fory_read_type_info(context, is_field)
+    fn fory_read_data(_: &mut ReadContext) -> Result<Self, Error> {
+        Err(Error::not_allowed("ArcWeak<T> should be written using `fory_read/fory_read_with_type_info` to handle reference tracking properly"))
+    }
+
+    fn fory_read_type_info(context: &mut ReadContext) -> Result<(), Error> {
+        T::fory_read_type_info(context)
     }
 
     fn fory_reserved_space() -> usize {
@@ -504,11 +556,76 @@ impl<T: Serializer + ForyDefault + Send + Sync + 'static> Serializer for ArcWeak
         }
     }
 
+    fn fory_static_type_id() -> TypeId {
+        T::fory_static_type_id()
+    }
+
     fn as_any(&self) -> &dyn std::any::Any {
         self
     }
 }
 
+fn read_arc_weak<T: Serializer + ForyDefault + 'static>(
+    context: &mut ReadContext,
+    read_ref_info: bool,
+    read_type_info: bool,
+    type_info: Option<Arc<TypeInfo>>,
+) -> Result<ArcWeak<T>, Error> {
+    let ref_flag = if read_ref_info {
+        context.ref_reader.read_ref_flag(&mut context.reader)?
+    } else {
+        RefFlag::NotNullValue
+    };
+    match ref_flag {
+        RefFlag::Null => Ok(ArcWeak::new()),
+        RefFlag::RefValue => {
+            context.inc_depth()?;
+            let data = if let Some(type_info) = type_info {
+                T::fory_read_with_type_info(context, false, type_info)?
+            } else {
+                if read_type_info {
+                    context.read_any_typeinfo()?;
+                }
+                T::fory_read_data(context)?
+            };
+            context.dec_depth();
+            let arc = Arc::new(data);
+            let ref_id = context.ref_reader.store_arc_ref(arc);
+            let arc = context.ref_reader.get_arc_ref::<T>(ref_id).unwrap();
+            let weak = ArcWeak::from(&arc);
+            Ok(weak)
+        }
+        RefFlag::Ref => {
+            let ref_id = context.ref_reader.read_ref_id(&mut context.reader)?;
+            let weak = ArcWeak::new();
+
+            if let Some(arc) = context.ref_reader.get_arc_ref::<T>(ref_id) {
+                weak.update(Arc::downgrade(&arc));
+            } else {
+                // Capture the raw pointer to the UnsafeCell so we can update it in the callback
+                let weak_ptr = weak.inner.get();
+                context.ref_reader.add_callback(Box::new(move |ref_reader| {
+                    if let Some(arc) = ref_reader.get_arc_ref::<T>(ref_id) {
+                        unsafe {
+                            *weak_ptr = Arc::downgrade(&arc);
+                        }
+                    }
+                }));
+            }
+            Ok(weak)
+        }
+        RefFlag::NotNullValue => {
+            // let inner = if let Some(typeinfo) = type_info {
+            //     T::fory_read_with_type_info(context, false, typeinfo)?
+            // } else {
+            //     T::fory_read_data(context)?
+            // };
+            // Ok(ArcWeak::from(&Arc::new(inner)))
+            Err(Error::invalid_ref("ArcWeak can't hold a strong ref value"))
+        }
+    }
+}
+
 impl<T: ForyDefault> ForyDefault for ArcWeak<T> {
     fn fory_default() -> Self {
         ArcWeak::new()
diff --git a/rust/fory-core/src/types.rs b/rust/fory-core/src/types.rs
index 14fc58534..e4f177a8d 100644
--- a/rust/fory-core/src/types.rs
+++ b/rust/fory-core/src/types.rs
@@ -82,10 +82,49 @@ pub enum TypeId {
     ARROW_RECORD_BATCH = 38,
     ARROW_TABLE = 39,
     UNKNOWN = 63,
-    // only used at receiver peer
-    ForyNullable = 265,
 }
 
+pub const BOOL: u32 = TypeId::BOOL as u32;
+pub const INT8: u32 = TypeId::INT8 as u32;
+pub const INT16: u32 = TypeId::INT16 as u32;
+pub const INT32: u32 = TypeId::INT32 as u32;
+pub const VAR_INT32: u32 = TypeId::VAR_INT32 as u32;
+pub const INT64: u32 = TypeId::INT64 as u32;
+pub const VAR_INT64: u32 = TypeId::VAR_INT64 as u32;
+pub const SLI_INT64: u32 = TypeId::SLI_INT64 as u32;
+pub const FLOAT16: u32 = TypeId::FLOAT16 as u32;
+pub const FLOAT32: u32 = TypeId::FLOAT32 as u32;
+pub const FLOAT64: u32 = TypeId::FLOAT64 as u32;
+pub const STRING: u32 = TypeId::STRING as u32;
+pub const ENUM: u32 = TypeId::ENUM as u32;
+pub const NAMED_ENUM: u32 = TypeId::NAMED_ENUM as u32;
+pub const STRUCT: u32 = TypeId::STRUCT as u32;
+pub const COMPATIBLE_STRUCT: u32 = TypeId::COMPATIBLE_STRUCT as u32;
+pub const NAMED_STRUCT: u32 = TypeId::NAMED_STRUCT as u32;
+pub const NAMED_COMPATIBLE_STRUCT: u32 = TypeId::NAMED_COMPATIBLE_STRUCT as u32;
+pub const EXT: u32 = TypeId::EXT as u32;
+pub const NAMED_EXT: u32 = TypeId::NAMED_EXT as u32;
+pub const LIST: u32 = TypeId::LIST as u32;
+pub const SET: u32 = TypeId::SET as u32;
+pub const MAP: u32 = TypeId::MAP as u32;
+pub const DURATION: u32 = TypeId::DURATION as u32;
+pub const TIMESTAMP: u32 = TypeId::TIMESTAMP as u32;
+pub const LOCAL_DATE: u32 = TypeId::LOCAL_DATE as u32;
+pub const DECIMAL: u32 = TypeId::DECIMAL as u32;
+pub const BINARY: u32 = TypeId::BINARY as u32;
+pub const ARRAY: u32 = TypeId::ARRAY as u32;
+pub const BOOL_ARRAY: u32 = TypeId::BOOL_ARRAY as u32;
+pub const INT8_ARRAY: u32 = TypeId::INT8_ARRAY as u32;
+pub const INT16_ARRAY: u32 = TypeId::INT16_ARRAY as u32;
+pub const INT32_ARRAY: u32 = TypeId::INT32_ARRAY as u32;
+pub const INT64_ARRAY: u32 = TypeId::INT64_ARRAY as u32;
+pub const FLOAT16_ARRAY: u32 = TypeId::FLOAT16_ARRAY as u32;
+pub const FLOAT32_ARRAY: u32 = TypeId::FLOAT32_ARRAY as u32;
+pub const FLOAT64_ARRAY: u32 = TypeId::FLOAT64_ARRAY as u32;
+pub const ARROW_RECORD_BATCH: u32 = TypeId::ARROW_RECORD_BATCH as u32;
+pub const ARROW_TABLE: u32 = TypeId::ARROW_TABLE as u32;
+pub const UNKNOWN: u32 = TypeId::UNKNOWN as u32;
+
 const MAX_UNT32: u64 = (1 << 31) - 1;
 
 // todo: struct hash
@@ -171,6 +210,24 @@ pub static PRIMITIVE_ARRAY_TYPE_MAP: &[(&str, u32, &str)] = &[
     ("f64", TypeId::FLOAT64_ARRAY as u32, "Vec<f64>"),
 ];
 
+#[inline(always)]
+pub fn is_primitive_type(type_id: TypeId) -> bool {
+    matches!(
+        type_id,
+        TypeId::BOOL
+            | TypeId::INT8
+            | TypeId::INT16
+            | TypeId::INT32
+            | TypeId::INT64
+            | TypeId::FLOAT32
+            | TypeId::FLOAT64
+            | TypeId::STRING
+            | TypeId::LOCAL_DATE
+            | TypeId::TIMESTAMP
+    )
+}
+
+#[inline(always)]
 pub fn is_internal_type(type_id: u32) -> bool {
     if type_id == 0 || type_id >= TypeId::UNKNOWN as u32 {
         return false;
@@ -188,6 +245,25 @@ pub fn is_internal_type(type_id: u32) -> bool {
     !excluded.contains(&type_id)
 }
 
+#[inline(always)]
+pub fn need_to_write_type_for_field(type_id: TypeId) -> bool {
+    matches!(
+        type_id,
+        TypeId::STRUCT
+            | TypeId::COMPATIBLE_STRUCT
+            | TypeId::NAMED_STRUCT
+            | TypeId::NAMED_COMPATIBLE_STRUCT
+            | TypeId::EXT
+            | TypeId::NAMED_EXT
+            | TypeId::UNKNOWN
+    )
+}
+
+#[inline(always)]
+pub fn is_container_type(type_id: TypeId) -> bool {
+    type_id == TypeId::LIST || type_id == TypeId::SET || type_id == TypeId::MAP
+}
+
 pub fn compute_field_hash(hash: u32, id: i16) -> u32 {
     let mut new_hash: u64 = (hash as u64) * 31 + (id as u64);
     while new_hash >= MAX_UNT32 {
@@ -252,9 +328,9 @@ impl TryFrom<u8> for Language {
             4 => Ok(Language::Go),
             5 => Ok(Language::Javascript),
             6 => Ok(Language::Rust),
-            _ => Err(Error::InvalidData(
-                format!("Unsupported language code, value:{num}").into(),
-            )),
+            _ => Err(Error::invalid_data(format!(
+                "Unsupported language code, value:{num}"
+            ))),
         }
     }
 }
diff --git a/rust/fory-derive/src/lib.rs b/rust/fory-derive/src/lib.rs
index 059fca439..0ef903e71 100644
--- a/rust/fory-derive/src/lib.rs
+++ b/rust/fory-derive/src/lib.rs
@@ -198,13 +198,18 @@ mod util;
 ///     city: String,
 /// }
 /// ```
-#[proc_macro_derive(ForyObject)]
+#[proc_macro_derive(ForyObject, attributes(fory_debug))]
 pub fn proc_macro_derive_fory_object(input: proc_macro::TokenStream) -> TokenStream {
     let input = parse_macro_input!(input as DeriveInput);
 
     // Check if this is being applied to a trait (which is not possible with derive macros)
     // Derive macros can only be applied to structs, enums, and unions
-    object::derive_serializer(&input)
+    let debug_enabled = input
+        .attrs
+        .iter()
+        .any(|attr| attr.path().is_ident("fory_debug"));
+
+    object::derive_serializer(&input, debug_enabled)
 }
 
 /// Derive macro for row-based serialization.
diff --git a/rust/fory-derive/src/object/derive_enum.rs b/rust/fory-derive/src/object/derive_enum.rs
index 61f7c0234..0027646d8 100644
--- a/rust/fory-derive/src/object/derive_enum.rs
+++ b/rust/fory-derive/src/object/derive_enum.rs
@@ -37,15 +37,9 @@ pub fn gen_reserved_space() -> TokenStream {
     }
 }
 
-pub fn gen_write_type_info() -> TokenStream {
-    quote! {
-        fory_core::serializer::enum_::write_type_info::<Self>(context, is_field)
-    }
-}
-
-pub fn gen_read_type_info() -> TokenStream {
+pub fn gen_write(_data_enum: &DataEnum) -> TokenStream {
     quote! {
-        fory_core::serializer::enum_::read_type_info::<Self>(context, is_field)
+        fory_core::serializer::enum_::write::<Self>(self, context, write_ref_info, write_type_info)
     }
 }
 
@@ -62,6 +56,23 @@ pub fn gen_write_data(data_enum: &DataEnum) -> TokenStream {
         })
     }
 }
+pub fn gen_write_type_info() -> TokenStream {
+    quote! {
+        fory_core::serializer::enum_::write_type_info::<Self>(context)
+    }
+}
+
+pub fn gen_read(_: &DataEnum) -> TokenStream {
+    quote! {
+        fory_core::serializer::enum_::read::<Self>(context, read_ref_info, read_type_info)
+    }
+}
+
+pub fn gen_read_with_type_info(_: &DataEnum) -> TokenStream {
+    quote! {
+        fory_core::serializer::enum_::read::<Self>(context, read_ref_info, false)
+    }
+}
 
 pub fn gen_read_data(data_enum: &DataEnum) -> TokenStream {
     let variant_idents: Vec<_> = data_enum.variants.iter().map(|v| &v.ident).collect();
@@ -72,25 +83,13 @@ pub fn gen_read_data(data_enum: &DataEnum) -> TokenStream {
            #(
                #variant_values => Ok(Self::#variant_idents),
            )*
-           _ => return Err(fory_core::error::Error::UnknownEnum("unknown enum value".into())),
+           _ => return Err(fory_core::error::Error::unknown_enum("unknown enum value")),
         }
     }
 }
 
-pub fn gen_read_compatible() -> TokenStream {
-    quote! {
-        fory_core::serializer::enum_::read_compatible::<Self>(context)
-    }
-}
-
-pub fn gen_write(_data_enum: &DataEnum) -> TokenStream {
-    quote! {
-        fory_core::serializer::enum_::write::<Self>(self, context, is_field)
-    }
-}
-
-pub fn gen_read(_data_enum: &DataEnum) -> TokenStream {
+pub fn gen_read_type_info() -> TokenStream {
     quote! {
-        fory_core::serializer::enum_::read::<Self>(context, is_field)
+        fory_core::serializer::enum_::read_type_info::<Self>(context)
     }
 }
diff --git a/rust/fory-derive/src/object/read.rs b/rust/fory-derive/src/object/read.rs
index e72ff3eed..03755e1fe 100644
--- a/rust/fory-derive/src/object/read.rs
+++ b/rust/fory-derive/src/object/read.rs
@@ -15,14 +15,14 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use fory_core::types::RefFlag;
 use proc_macro2::{Ident, TokenStream};
 use quote::{format_ident, quote};
 use syn::{Field, Type};
 
 use super::util::{
     classify_trait_object_field, create_wrapper_types_arc, create_wrapper_types_rc,
-    extract_type_name, is_primitive_type, parse_generic_tree, skip_ref_flag, StructField,
+    extract_type_name, get_struct_name, is_debug_enabled, is_primitive_type,
+    should_skip_type_info_for_field, skip_ref_flag, StructField,
 };
 
 fn create_private_field_name(field: &Field) -> Ident {
@@ -41,7 +41,7 @@ fn declare_var(fields: &[&Field]) -> Vec<TokenStream> {
             let ty = &field.ty;
             let var_name = create_private_field_name(field);
             match classify_trait_object_field(ty) {
-                StructField::BoxDyn(_)
+                StructField::BoxDyn
                 | StructField::RcDyn(_)
                 | StructField::ArcDyn(_) => {
                     quote! {
@@ -75,7 +75,7 @@ fn assign_value(fields: &[&Field]) -> Vec<TokenStream> {
             let name = &field.ident;
             let var_name = create_private_field_name(field);
             match classify_trait_object_field(&field.ty) {
-                StructField::BoxDyn(_) | StructField::RcDyn(_) | StructField::ArcDyn(_) => {
+                StructField::BoxDyn | StructField::RcDyn(_) | StructField::ArcDyn(_) => {
                     quote! {
                         #name: #var_name
                     }
@@ -103,28 +103,10 @@ fn assign_value(fields: &[&Field]) -> Vec<TokenStream> {
 
 fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
     let ty = &field.ty;
-    match classify_trait_object_field(ty) {
-        StructField::BoxDyn(trait_name) => {
-            let from_any_fn = format_ident!("from_any_internal_{}", trait_name);
-            let helper_mod = format_ident!("__fory_trait_helpers_{}", trait_name);
+    let base = match classify_trait_object_field(ty) {
+        StructField::BoxDyn => {
             quote! {
-                let ref_flag = context.reader.read_i8()?;
-                if ref_flag != fory_core::types::RefFlag::NotNullValue as i8 {
-                    return Err(Error::InvalidRef("Expected NotNullValue for trait object field".into()));
-                }
-
-                let fory_type_id = context.reader.read_varuint32()?;
-
-                let harness = context.get_type_resolver()
-                    .get_harness(fory_type_id)
-                    .ok_or_else(|| Error::TypeError("Type not registered for trait object field".into()))?;
-
-                let deserializer_fn = harness.get_read_fn();
-                let any_box = deserializer_fn(context, true, false)?;
-
-                let base_type_id = fory_type_id >> 8;
-                let #private_ident = #helper_mod::#from_any_fn(any_box, base_type_id)?;
-
+                let #private_ident = <#ty as fory_core::Serializer>::fory_read(context, true, true)?;
             }
         }
         StructField::RcDyn(trait_name) => {
@@ -132,7 +114,7 @@ fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper = <#wrapper_ty as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper = <#wrapper_ty as fory_core::Serializer>::fory_read(context, true, true)?;
                 let #private_ident = std::rc::Rc::<dyn #trait_ident>::from(wrapper);
             }
         }
@@ -141,7 +123,7 @@ fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper = <#wrapper_ty as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper = <#wrapper_ty as fory_core::Serializer>::fory_read(context, true, true)?;
                 let #private_ident = std::sync::Arc::<dyn #trait_ident>::from(wrapper);
             }
         }
@@ -150,7 +132,7 @@ fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 let #private_ident = wrapper_vec.into_iter()
                     .map(|w| std::rc::Rc::<dyn #trait_ident>::from(w))
                     .collect();
@@ -161,7 +143,7 @@ fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 let #private_ident = wrapper_vec.into_iter()
                     .map(|w| std::sync::Arc::<dyn #trait_ident>::from(w))
                     .collect();
@@ -172,7 +154,7 @@ fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 let #private_ident = wrapper_map.into_iter()
                     .map(|(k, v)| (k, std::rc::Rc::<dyn #trait_ident>::from(v)))
                     .collect();
@@ -183,7 +165,7 @@ fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 let #private_ident = wrapper_map.into_iter()
                     .map(|(k, v)| (k, std::sync::Arc::<dyn #trait_ident>::from(v)))
                     .collect();
@@ -191,21 +173,60 @@ fn gen_read_field(field: &Field, private_ident: &Ident) -> TokenStream {
         }
         StructField::Forward => {
             quote! {
-                let #private_ident = fory_core::serializer::Serializer::fory_read(context, true)?;
+                let #private_ident = <#ty as fory_core::Serializer>::fory_read(context, true, true)?;
             }
         }
         _ => {
             let skip_ref_flag = skip_ref_flag(ty);
-            quote! {
-                let #private_ident = fory_core::serializer::read_ref_info_data::<#ty>(context, true, #skip_ref_flag, false)?;
+            let skip_type_info = should_skip_type_info_for_field(ty);
+            if skip_type_info {
+                // Known types (primitives, strings, collections) - skip type info at compile time
+                if skip_ref_flag {
+                    quote! {
+                        let #private_ident = <#ty as fory_core::Serializer>::fory_read_data(context)?;
+                    }
+                } else {
+                    quote! {
+                        let #private_ident = <#ty as fory_core::Serializer>::fory_read(context, true, false)?;
+                    }
+                }
+            } else {
+                // Custom types (struct/enum/ext) - need runtime check for enums
+                quote! {
+                    let is_enum = <#ty as fory_core::Serializer>::fory_static_type_id() == fory_core::types::TypeId::ENUM;
+                    let #private_ident = <#ty as fory_core::Serializer>::fory_read(context, true, !is_enum)?;
+                }
             }
         }
+    };
+
+    if is_debug_enabled() {
+        let struct_name = get_struct_name().expect("struct context not set");
+        let struct_name_lit = syn::LitStr::new(&struct_name, proc_macro2::Span::call_site());
+        let field_name = field.ident.as_ref().unwrap().to_string();
+        let field_name_lit = syn::LitStr::new(&field_name, proc_macro2::Span::call_site());
+        quote! {
+            fory_core::serializer::struct_::struct_before_read_field(
+                #struct_name_lit,
+                #field_name_lit,
+                context,
+            );
+            #base
+            fory_core::serializer::struct_::struct_after_read_field(
+                #struct_name_lit,
+                #field_name_lit,
+                (&#private_ident) as &dyn std::any::Any,
+                context,
+            );
+        }
+    } else {
+        base
     }
 }
 
 pub fn gen_read_type_info() -> TokenStream {
     quote! {
-        fory_core::serializer::struct_::read_type_info::<Self>(context, is_field)
+        fory_core::serializer::struct_::read_type_info::<Self>(context)
     }
 }
 
@@ -248,24 +269,12 @@ pub fn gen_read_data(fields: &[&Field]) -> TokenStream {
 
 fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenStream {
     let ty = &field.ty;
+    let field_kind = classify_trait_object_field(ty);
 
-    match classify_trait_object_field(ty) {
-        StructField::BoxDyn(trait_name) => {
-            let from_any_fn = format_ident!("from_any_internal_{}", trait_name);
-            let helper_mod = format_ident!("__fory_trait_helpers_{}", trait_name);
+    let base = match field_kind {
+        StructField::BoxDyn => {
             quote! {
-                let ref_flag = context.reader.read_i8()?;
-                if ref_flag != fory_core::types::RefFlag::NotNullValue as i8 {
-                    return Err(Error::InvalidRef("Expected NotNullValue for trait object field".into()));
-                }
-                let fory_type_id = context.reader.read_varuint32()?;
-                let harness = context.get_type_resolver()
-                    .get_harness(fory_type_id)
-                    .ok_or_else(|| Error::TypeError("Type not registered for trait object field".into()))?;
-                let deserializer_fn = harness.get_read_fn();
-                let any_box = deserializer_fn(context, true, false)?;
-                let base_type_id = fory_type_id >> 8;
-                #var_name = #helper_mod::#from_any_fn(any_box, base_type_id)?;
+                #var_name = Some(<#ty as fory_core::Serializer>::fory_read(context, true, true)?);
             }
         }
         StructField::RcDyn(trait_name) => {
@@ -273,7 +282,7 @@ fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenS
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper = <#wrapper_ty as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper = <#wrapper_ty as fory_core::Serializer>::fory_read(context, true, true)?;
                 #var_name = Some(std::rc::Rc::<dyn #trait_ident>::from(wrapper));
             }
         }
@@ -282,7 +291,7 @@ fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenS
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper = <#wrapper_ty as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper = <#wrapper_ty as fory_core::Serializer>::fory_read(context, true, true)?;
                 #var_name = Some(std::sync::Arc::<dyn #trait_ident>::from(wrapper));
             }
         }
@@ -291,7 +300,7 @@ fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenS
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 #var_name = Some(wrapper_vec.into_iter()
                     .map(|w| std::rc::Rc::<dyn #trait_ident>::from(w))
                     .collect());
@@ -302,7 +311,7 @@ fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenS
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_vec = <Vec<#wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 #var_name = Some(wrapper_vec.into_iter()
                     .map(|w| std::sync::Arc::<dyn #trait_ident>::from(w))
                     .collect());
@@ -313,7 +322,7 @@ fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenS
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 #var_name = Some(wrapper_map.into_iter()
                     .map(|(k, v)| (k, std::rc::Rc::<dyn #trait_ident>::from(v)))
                     .collect());
@@ -324,7 +333,7 @@ fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenS
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::serializer::Serializer>::fory_read(context, true)?;
+                let wrapper_map = <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_read(context, true, false)?;
                 #var_name = Some(wrapper_map.into_iter()
                     .map(|(k, v)| (k, std::sync::Arc::<dyn #trait_ident>::from(v)))
                     .collect());
@@ -332,78 +341,155 @@ fn gen_read_compatible_match_arm_body(field: &Field, var_name: &Ident) -> TokenS
         }
         StructField::ContainsTraitObject => {
             quote! {
-                let skip_ref_flag = fory_core::serializer::get_skip_ref_flag::<#ty>(context.get_type_resolver());
-                #var_name = Some(fory_core::serializer::read_ref_info_data::<#ty>(context, true, skip_ref_flag, false)?);
+                #var_name = Some(<#ty as fory_core::Serializer>::fory_read(context, true, true)?);
             }
         }
         StructField::Forward => {
             quote! {
-                #var_name = Some(fory_core::serializer::Serializer::fory_read(context, true)?);
+                #var_name = Some(<#ty as fory_core::Serializer>::fory_read(context, true, true)?);
             }
         }
         StructField::None => {
-            let generic_tree = parse_generic_tree(ty);
-            let local_nullable = generic_tree.name == "Option";
             let _base_ty = match &ty {
                 Type::Path(type_path) => &type_path.path.segments.first().unwrap().ident,
                 _ => panic!("Unsupported type"),
             };
-            if local_nullable {
-                quote! {
-                    if _field.field_type.nullable {
-                        #var_name = Some(fory_core::serializer::read_ref_info_data::<#ty>(context, true, false, false)?);
-                    } else {
-                        #var_name = Some(
-                            fory_core::serializer::read_ref_info_data::<#ty>(context, true, true, false)?
-                        );
-                    }
-                }
-            } else {
-                let dec_by_option = need_declared_by_option(field);
+            let skip_type_info = should_skip_type_info_for_field(ty);
+            let dec_by_option = need_declared_by_option(field);
+            if skip_type_info {
                 if dec_by_option {
                     quote! {
-                        if !_field.field_type.nullable {
-                            #var_name = Some(fory_core::serializer::read_ref_info_data::<#ty>(context, true, true, false)?);
+                        let read_ref_flag = fory_core::serializer::util::field_requires_ref_flag(
+                            _field.field_type.type_id,
+                            _field.field_type.nullable,
+                        );
+                        if read_ref_flag {
+                            #var_name = Some(<#ty as fory_core::Serializer>::fory_read(context, true, false)?);
                         } else {
-                            #var_name = fory_core::serializer::read_ref_info_data::<Option<#ty>>(context, true, false, false)?
+                            #var_name = Some(<#ty as fory_core::Serializer>::fory_read_data(context)?);
                         }
                     }
                 } else {
-                    let null_flag = RefFlag::Null as i8;
                     quote! {
-                        if !_field.field_type.nullable {
-                            #var_name = fory_core::serializer::read_ref_info_data::<#ty>(context, true, true, false)?;
+                        let read_ref_flag = fory_core::serializer::util::field_requires_ref_flag(
+                            _field.field_type.type_id,
+                            _field.field_type.nullable,
+                        );
+                        if read_ref_flag {
+                            #var_name = <#ty as fory_core::Serializer>::fory_read(context, true, false)?;
                         } else {
-                            if context.reader.read_i8()? == #null_flag {
-                                #var_name = <#ty as fory_core::serializer::ForyDefault>::fory_default();
-                            } else {
-                                #var_name = fory_core::serializer::read_ref_info_data::<#ty>(context, true, true, false)?;
-                            }
+                            #var_name = <#ty as fory_core::Serializer>::fory_read_data(context)?;
                         }
                     }
                 }
+            } else if dec_by_option {
+                quote! {
+                    let skip_type_info = fory_core::serializer::util::should_skip_type_info_at_runtime(_field.field_type.type_id);
+                    let read_ref_flag = fory_core::serializer::util::field_requires_ref_flag(
+                        _field.field_type.type_id,
+                        _field.field_type.nullable,
+                    );
+                    if read_ref_flag {
+                        #var_name = Some(<#ty as fory_core::Serializer>::fory_read(context, true, !skip_type_info)?);
+                    } else {
+                        #var_name = Some(<#ty as fory_core::Serializer>::fory_read_data(context)?);
+                    }
+                }
+            } else {
+                quote! {
+                    let skip_type_info = fory_core::serializer::util::should_skip_type_info_at_runtime(_field.field_type.type_id);
+                    let read_ref_flag = fory_core::serializer::util::field_requires_ref_flag(
+                        _field.field_type.type_id,
+                        _field.field_type.nullable,
+                    );
+                    if read_ref_flag {
+                        #var_name = <#ty as fory_core::Serializer>::fory_read(context, true, !skip_type_info)?;
+                    } else {
+                        #var_name = <#ty as fory_core::Serializer>::fory_read_data(context)?;
+                    }
+                }
             }
         }
+    };
+
+    if is_debug_enabled() {
+        let struct_name = get_struct_name().expect("struct context not set");
+        let struct_name_lit = syn::LitStr::new(&struct_name, proc_macro2::Span::call_site());
+        let field_name = field.ident.as_ref().unwrap().to_string();
+        let field_name_lit = syn::LitStr::new(&field_name, proc_macro2::Span::call_site());
+        quote! {
+            fory_core::serializer::struct_::struct_before_read_field(
+                #struct_name_lit,
+                #field_name_lit,
+                context,
+            );
+            #base
+            fory_core::serializer::struct_::struct_after_read_field(
+                #struct_name_lit,
+                #field_name_lit,
+                (&#var_name) as &dyn std::any::Any,
+                context,
+            );
+        }
+    } else {
+        quote! {
+            #base
+        }
     }
 }
 
 pub fn gen_read(struct_ident: &Ident) -> TokenStream {
     quote! {
-        let ref_flag = context.reader.read_i8()?;
-        if ref_flag == (fory_core::types::RefFlag::NotNullValue as i8) || ref_flag == (fory_core::types::RefFlag::RefValue as i8) {
+        let ref_flag = if read_ref_info {
+            context.reader.read_i8()?
+        } else {
+            fory_core::RefFlag::NotNullValue as i8
+        };
+        if ref_flag == (fory_core::RefFlag::NotNullValue as i8) || ref_flag == (fory_core::RefFlag::RefValue as i8) {
+            if context.is_compatible() {
+                let type_info = if read_type_info {
+                    context.read_any_typeinfo()?
+                } else {
+                    let rs_type_id = std::any::TypeId::of::<Self>();
+                    context.get_type_info(&rs_type_id)?
+                };
+                <#struct_ident as fory_core::StructSerializer>::fory_read_compatible(context, type_info)
+            } else {
+                if read_type_info {
+                    <Self as fory_core::Serializer>::fory_read_type_info(context)?;
+                }
+                <Self as fory_core::Serializer>::fory_read_data(context)
+            }
+        } else if ref_flag == (fory_core::RefFlag::Null as i8) {
+            Ok(<Self as fory_core::ForyDefault>::fory_default())
+        } else {
+            Err(fory_core::error::Error::invalid_ref(format!("Unknown ref flag, value:{ref_flag}")))
+        }
+    }
+}
+
+pub fn gen_read_with_type_info(struct_ident: &Ident) -> TokenStream {
+    // fn fory_read_with_type_info(
+    //     context: &mut ReadContext,
+    //     read_ref_info: bool,
+    //     type_info: Arc<TypeInfo>,
+    // ) -> Result<Self, Error>
+    quote! {
+        let ref_flag = if read_ref_info {
+            context.reader.read_i8()?
+        } else {
+            fory_core::RefFlag::NotNullValue as i8
+        };
+        if ref_flag == (fory_core::RefFlag::NotNullValue as i8) || ref_flag == (fory_core::RefFlag::RefValue as i8) {
             if context.is_compatible() {
-                <#struct_ident as fory_core::serializer::Serializer>::fory_read_compatible(context)
+                <#struct_ident as fory_core::StructSerializer>::fory_read_compatible(context, type_info)
             } else {
-                <Self as fory_core::serializer::Serializer>::fory_read_type_info(context, false)?;
-                <Self as fory_core::serializer::Serializer>::fory_read_data(context, false)
+                <Self as fory_core::Serializer>::fory_read_data(context)
             }
-        } else if ref_flag == (fory_core::types::RefFlag::Null as i8) {
-            Ok(<Self as fory_core::serializer::ForyDefault>::fory_default())
-        } else if ref_flag == (fory_core::types::RefFlag::Ref as i8) {
-            // Err(fory_core::error::Error::Ref)
-            todo!()
+        } else if ref_flag == (fory_core::RefFlag::Null as i8) {
+            Ok(<Self as fory_core::ForyDefault>::fory_default())
         } else {
-            Err(fory_core::error::Error::InvalidRef(format!("Unknown ref flag, value:{ref_flag}").into()))
+            Err(fory_core::error::Error::invalid_ref(format!("Unknown ref flag, value:{ref_flag}")))
         }
     }
 }
@@ -427,28 +513,58 @@ pub fn gen_read_compatible(fields: &[&Field]) -> TokenStream {
         })
         .collect();
 
+    let skip_arm = if is_debug_enabled() {
+        let struct_name = get_struct_name().expect("struct context not set");
+        let struct_name_lit = syn::LitStr::new(&struct_name, proc_macro2::Span::call_site());
+        quote! {
+            _ => {
+                let field_type = &_field.field_type;
+                let read_ref_flag = fory_core::serializer::util::field_requires_ref_flag(
+                    field_type.type_id,
+                    field_type.nullable,
+                );
+                let field_name = _field.field_name.as_str();
+                fory_core::serializer::struct_::struct_before_read_field(
+                    #struct_name_lit,
+                    field_name,
+                    context,
+                );
+                fory_core::serializer::skip::skip_field_value(context, &field_type, read_ref_flag)?;
+                let placeholder: &dyn std::any::Any = &();
+                fory_core::serializer::struct_::struct_after_read_field(
+                    #struct_name_lit,
+                    field_name,
+                    placeholder,
+                    context,
+                );
+            }
+        }
+    } else {
+        quote! {
+            _ => {
+                let field_type = &_field.field_type;
+                let read_ref_flag = fory_core::serializer::util::field_requires_ref_flag(
+                    field_type.type_id,
+                    field_type.nullable,
+                );
+                fory_core::serializer::skip::skip_field_value(context, field_type, read_ref_flag)?;
+            }
+        }
+    };
+
     quote! {
-        let remote_type_id = context.reader.read_varuint32()?;
-        let meta_index = context.reader.read_varuint32()?;
-        let meta = context.get_meta(meta_index as usize);
-        let fields = {
-            let meta = context.get_meta(meta_index as usize);
-            meta.get_field_infos().clone()
-        };
+        let fields = type_info.get_type_meta().get_field_infos().clone();
         #(#declare_ts)*
-
-        let local_type_hash = context.get_type_resolver().get_type_info(std::any::TypeId::of::<Self>())?.get_type_meta().get_hash();
-        if meta.get_hash() == local_type_hash {
-            <Self as fory_core::serializer::Serializer>::fory_read_data(context, false)
+        let meta = context.get_type_info(&std::any::TypeId::of::<Self>())?.get_type_meta();
+        let local_type_hash = meta.get_hash();
+        let remote_type_hash = type_info.get_type_meta().get_hash();
+        if remote_type_hash == local_type_hash {
+            <Self as fory_core::Serializer>::fory_read_data(context)
         } else {
             for _field in fields.iter() {
                 match _field.field_id {
                     #(#match_arms)*
-                    _ => {
-                        let field_type = &_field.field_type;
-                        let read_ref_flag = fory_core::serializer::skip::get_read_ref_flag(&field_type);
-                        fory_core::serializer::skip::skip_field_value(context, &field_type, read_ref_flag)?;
-                    }
+                    #skip_arm
                 }
             }
             Ok(Self {
diff --git a/rust/fory-derive/src/object/serializer.rs b/rust/fory-derive/src/object/serializer.rs
index 2ba9b9513..51a1ae131 100644
--- a/rust/fory-derive/src/object/serializer.rs
+++ b/rust/fory-derive/src/object/serializer.rs
@@ -36,10 +36,10 @@ fn has_existing_default(ast: &syn::DeriveInput, trait_name: &str) -> bool {
     })
 }
 
-pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
+pub fn derive_serializer(ast: &syn::DeriveInput, debug_enabled: bool) -> TokenStream {
     let name = &ast.ident;
     use crate::object::util::{clear_struct_context, set_struct_context};
-    set_struct_context(&name.to_string());
+    set_struct_context(&name.to_string(), debug_enabled);
 
     // Check if ForyDefault is already derived/implemented
     let has_existing_default = has_existing_default(ast, "ForyDefault");
@@ -65,7 +65,10 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
                 derive_enum::gen_actual_type_id(),
                 quote! { &[] },
                 derive_enum::gen_field_fields_info(s),
-                derive_enum::gen_read_compatible(),
+                quote! {
+                    Err(fory_core::Error::not_allowed("`fory_read_compatible` should only be invoked at struct type"
+                ))
+                },
             ),
             syn::Data::Union(_) => {
                 panic!("Union is not supported")
@@ -73,34 +76,40 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
         };
     // Serializer
     let (
-        reserved_space_ts,
-        write_type_info_ts,
-        read_type_info_ts,
-        write_data_ts,
-        read_data_ts,
         write_ts,
+        write_data_ts,
+        write_type_info_ts,
         read_ts,
+        read_with_type_info_ts,
+        read_data_ts,
+        read_type_info_ts,
+        reserved_space_ts,
+        static_type_id_ts,
     ) = match &ast.data {
         syn::Data::Struct(s) => {
             let fields = sorted_fields(&s.fields);
             (
-                write::gen_reserved_space(&fields),
-                write::gen_write_type_info(),
-                read::gen_read_type_info(),
-                write::gen_write_data(&fields),
-                read::gen_read_data(&fields),
                 write::gen_write(),
+                write::gen_write_data(&fields),
+                write::gen_write_type_info(),
                 read::gen_read(name),
+                read::gen_read_with_type_info(name),
+                read::gen_read_data(&fields),
+                read::gen_read_type_info(),
+                write::gen_reserved_space(&fields),
+                quote! { fory_core::TypeId::STRUCT },
             )
         }
         syn::Data::Enum(e) => (
-            derive_enum::gen_reserved_space(),
-            derive_enum::gen_write_type_info(),
-            derive_enum::gen_read_type_info(),
-            derive_enum::gen_write_data(e),
-            derive_enum::gen_read_data(e),
             derive_enum::gen_write(e),
+            derive_enum::gen_write_data(e),
+            derive_enum::gen_write_type_info(),
             derive_enum::gen_read(e),
+            derive_enum::gen_read_with_type_info(e),
+            derive_enum::gen_read_data(e),
+            derive_enum::gen_read_type_info(),
+            derive_enum::gen_reserved_space(),
+            quote! { fory_core::TypeId::ENUM },
         ),
         syn::Data::Union(_) => {
             panic!("Union is not supported")
@@ -111,11 +120,11 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
     let type_idx = misc::allocate_type_id();
 
     let gen = quote! {
-        use fory_core::serializer::ForyDefault as _;
+        use fory_core::ForyDefault as _;
 
         #default_impl
 
-        impl fory_core::serializer::StructSerializer for #name {
+        impl fory_core::StructSerializer for #name {
             fn fory_type_index() -> u32 {
                 #type_idx
             }
@@ -131,8 +140,13 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
             fn fory_fields_info(type_resolver: &fory_core::resolver::type_resolver::TypeResolver) -> Result<Vec<fory_core::meta::FieldInfo>, fory_core::error::Error> {
                 #fields_info_ts
             }
+
+            fn fory_read_compatible(context: &mut fory_core::resolver::context::ReadContext, type_info: std::sync::Arc<fory_core::TypeInfo>) -> Result<Self, fory_core::error::Error> {
+                #read_compatible_ts
+            }
         }
-        impl fory_core::serializer::Serializer for #name {
+
+        impl fory_core::Serializer for #name {
             fn fory_get_type_id(type_resolver: &fory_core::resolver::type_resolver::TypeResolver) -> Result<u32, fory_core::error::Error> {
                 type_resolver.get_type_id(&std::any::TypeId::of::<Self>(), #type_idx)
             }
@@ -145,36 +159,43 @@ pub fn derive_serializer(ast: &syn::DeriveInput) -> TokenStream {
                 self
             }
 
+            fn fory_static_type_id() -> fory_core::TypeId
+            where
+                Self: Sized,
+            {
+                #static_type_id_ts
+            }
+
             fn fory_reserved_space() -> usize {
                 #reserved_space_ts
             }
 
-            fn fory_write_type_info(context: &mut fory_core::resolver::context::WriteContext, is_field: bool) -> Result<(), fory_core::error::Error> {
-                #write_type_info_ts
+            fn fory_write(&self, context: &mut fory_core::resolver::context::WriteContext, write_ref_info: bool, write_type_info: bool, _: bool) -> Result<(), fory_core::error::Error> {
+                #write_ts
             }
 
-            fn fory_read_type_info(context: &mut fory_core::resolver::context::ReadContext, is_field: bool) -> Result<(), fory_core::error::Error> {
-                #read_type_info_ts
+            fn fory_write_data(&self, context: &mut fory_core::resolver::context::WriteContext) -> Result<(), fory_core::error::Error> {
+                #write_data_ts
             }
 
-            fn fory_write_data(&self, context: &mut fory_core::resolver::context::WriteContext, is_field: bool) -> Result<(), fory_core::error::Error> {
-                #write_data_ts
+            fn fory_write_type_info(context: &mut fory_core::resolver::context::WriteContext) -> Result<(), fory_core::error::Error> {
+                #write_type_info_ts
             }
 
-            fn fory_read_data( context: &mut fory_core::resolver::context::ReadContext, is_field: bool) -> Result<Self, fory_core::error::Error> {
-                #read_data_ts
+            fn fory_read(context: &mut fory_core::resolver::context::ReadContext, read_ref_info: bool, read_type_info: bool) -> Result<Self, fory_core::error::Error> {
+                #read_ts
             }
 
-            fn fory_write(&self, context: &mut fory_core::resolver::context::WriteContext, is_field: bool) -> Result<(), fory_core::error::Error> {
-                #write_ts
+            fn fory_read_with_type_info(context: &mut fory_core::resolver::context::ReadContext, read_ref_info: bool, type_info: std::sync::Arc<fory_core::TypeInfo>) -> Result<Self, fory_core::error::Error> {
+                #read_with_type_info_ts
             }
 
-            fn fory_read(context: &mut fory_core::resolver::context::ReadContext, is_field: bool) -> Result<Self, fory_core::error::Error> {
-                #read_ts
+            fn fory_read_data( context: &mut fory_core::resolver::context::ReadContext) -> Result<Self, fory_core::error::Error> {
+                #read_data_ts
             }
 
-            fn fory_read_compatible(context: &mut fory_core::resolver::context::ReadContext) -> Result<Self, fory_core::error::Error> {
-                #read_compatible_ts
+            fn fory_read_type_info(context: &mut fory_core::resolver::context::ReadContext) -> Result<(), fory_core::error::Error> {
+                #read_type_info_ts
             }
         }
     };
@@ -225,12 +246,12 @@ fn generate_default_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
                     }
                     StructField::Forward => {
                         quote! {
-                            #ident: <#ty as fory_core::serializer::ForyDefault>::fory_default()
+                            #ident: <#ty as fory_core::ForyDefault>::fory_default()
                         }
                     }
                     _ => {
                         quote! {
-                            #ident: <#ty as fory_core::serializer::ForyDefault>::fory_default()
+                            #ident: <#ty as fory_core::ForyDefault>::fory_default()
                         }
                     }
                 }
@@ -238,7 +259,7 @@ fn generate_default_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
 
             if has_existing_default {
                 quote! {
-                   impl fory_core::serializer::ForyDefault for #name {
+                   impl fory_core::ForyDefault for #name {
                         fn fory_default() -> Self {
                             Self::default()
                         }
@@ -246,7 +267,7 @@ fn generate_default_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
                 }
             } else {
                 quote! {
-                    impl fory_core::serializer::ForyDefault for #name {
+                    impl fory_core::ForyDefault for #name {
                         fn fory_default() -> Self {
                             Self {
                                 #(#field_inits),*
@@ -274,7 +295,7 @@ fn generate_default_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
                 if let Some(first_variant) = e.variants.first() {
                     let variant_ident = &first_variant.ident;
                     quote! {
-                        impl fory_core::serializer::ForyDefault for #name {
+                        impl fory_core::ForyDefault for #name {
                             fn fory_default() -> Self {
                                 Self::#variant_ident
                             }
@@ -287,7 +308,7 @@ fn generate_default_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
                         }
                     }
                 } else {
-                    // impl fory_core::serializer::ForyDefault for #name {
+                    // impl fory_core::ForyDefault for #name {
                     //     fn fory_default() -> Self {
                     //         panic!("No unit-like variants found in enum {}", stringify!(#name));
                     //     }
@@ -296,7 +317,7 @@ fn generate_default_impl(ast: &syn::DeriveInput) -> proc_macro2::TokenStream {
                 }
             } else {
                 quote! {
-                    impl fory_core::serializer::ForyDefault for #name {
+                    impl fory_core::ForyDefault for #name {
                         fn fory_default() -> Self {
                             Self::default()
                         }
diff --git a/rust/fory-derive/src/object/util.rs b/rust/fory-derive/src/object/util.rs
index ee5e0a585..0ef41a93e 100644
--- a/rust/fory-derive/src/object/util.rs
+++ b/rust/fory-derive/src/object/util.rs
@@ -30,14 +30,17 @@ thread_local! {
     static MACRO_CONTEXT: RefCell<Option<MacroContext>> = const {RefCell::new(None)};
 }
 
+#[derive(Clone)]
 struct MacroContext {
     struct_name: String,
+    debug_enabled: bool,
 }
 
-pub(super) fn set_struct_context(name: &str) {
+pub(super) fn set_struct_context(name: &str, debug_enabled: bool) {
     MACRO_CONTEXT.with(|ctx| {
         *ctx.borrow_mut() = Some(MacroContext {
             struct_name: name.to_string(),
+            debug_enabled,
         });
     });
 }
@@ -48,10 +51,19 @@ pub(super) fn clear_struct_context() {
     });
 }
 
-fn get_struct_name() -> Option<String> {
+pub(super) fn get_struct_name() -> Option<String> {
     MACRO_CONTEXT.with(|ctx| ctx.borrow().as_ref().map(|c| c.struct_name.clone()))
 }
 
+pub(super) fn is_debug_enabled() -> bool {
+    MACRO_CONTEXT.with(|ctx| {
+        ctx.borrow()
+            .as_ref()
+            .map(|c| c.debug_enabled)
+            .unwrap_or(false)
+    })
+}
+
 pub(super) fn contains_trait_object(ty: &Type) -> bool {
     match ty {
         Type::TraitObject(_) => true,
@@ -100,7 +112,8 @@ pub(super) fn create_wrapper_types_arc(trait_name: &str) -> WrapperTypes {
 }
 
 pub(super) enum StructField {
-    BoxDyn(String),
+    #[allow(unused_variables)]
+    BoxDyn,
     RcDyn(String),
     ArcDyn(String),
     VecRc(String),
@@ -187,8 +200,8 @@ pub(super) fn classify_trait_object_field(ty: &Type) -> StructField {
     if is_forward_field(ty) {
         return StructField::Forward;
     }
-    if let Some((_, trait_name)) = is_box_dyn_trait(ty) {
-        return StructField::BoxDyn(trait_name);
+    if let Some((_, _)) = is_box_dyn_trait(ty) {
+        return StructField::BoxDyn;
     }
     if let Some((_, trait_name)) = is_rc_dyn_trait(ty) {
         return StructField::RcDyn(trait_name);
@@ -278,6 +291,18 @@ pub(super) fn extract_type_name(ty: &Type) -> String {
     }
 }
 
+#[allow(dead_code)]
+pub(super) fn is_option(ty: &Type) -> bool {
+    if let Type::Path(type_path) = ty {
+        if let Some(seg) = type_path.path.segments.last() {
+            if seg.ident == "Option" {
+                return true;
+            }
+        }
+    }
+    false
+}
+
 pub(super) fn parse_generic_tree(ty: &Type) -> TypeNode {
     // Handle trait objects specially - they can't be parsed as normal types
     if matches!(ty, Type::TraitObject(_)) {
@@ -378,6 +403,10 @@ type FieldGroups = (
     FieldGroup,
 );
 
+fn extract_option_inner(s: &str) -> Option<&str> {
+    s.strip_prefix("Option<")?.strip_suffix(">")
+}
+
 const PRIMITIVE_TYPE_NAMES: [&str; 7] = ["bool", "i8", "i16", "i32", "i64", "f32", "f64"];
 
 fn get_primitive_type_id(ty: &str) -> u32 {
@@ -397,11 +426,121 @@ pub(super) fn is_primitive_type(ty: &str) -> bool {
     PRIMITIVE_TYPE_NAMES.contains(&ty)
 }
 
-fn group_fields_by_type(fields: &[&Field]) -> FieldGroups {
-    fn extract_option_inner(s: &str) -> Option<&str> {
-        s.strip_prefix("Option<")?.strip_suffix(">")
+pub(crate) fn get_type_id_by_type_ast(ty: &Type) -> u32 {
+    let ty_str: String = ty
+        .to_token_stream()
+        .to_string()
+        .chars()
+        .filter(|c| !c.is_whitespace())
+        .collect::<String>();
+    get_type_id_by_name(&ty_str)
+}
+
+/// Get the type ID for a given type string.
+///
+/// Returns:
+/// - `type_id` for known types (primitives, internal types, collections)
+/// - `UNKNOWN` for unknown/user-defined types
+pub(crate) fn get_type_id_by_name(ty: &str) -> u32 {
+    let ty = extract_option_inner(ty).unwrap_or(ty);
+    // Check primitive types
+    if PRIMITIVE_TYPE_NAMES.contains(&ty) {
+        return get_primitive_type_id(ty);
+    }
+
+    // Check internal types
+    match ty {
+        "String" => return TypeId::STRING as u32,
+        "NaiveDate" => return TypeId::LOCAL_DATE as u32,
+        "NaiveDateTime" => return TypeId::TIMESTAMP as u32,
+        "Duration" => return TypeId::DURATION as u32,
+        "Decimal" => return TypeId::DECIMAL as u32,
+        "Vec<u8>" | "bytes" => return TypeId::BINARY as u32,
+        _ => {}
+    }
+
+    // Check primitive arrays
+    match ty {
+        "Vec<bool>" => return TypeId::BOOL_ARRAY as u32,
+        "Vec<i8>" => return TypeId::INT8_ARRAY as u32,
+        "Vec<i16>" => return TypeId::INT16_ARRAY as u32,
+        "Vec<i32>" => return TypeId::INT32_ARRAY as u32,
+        "Vec<i64>" => return TypeId::INT64_ARRAY as u32,
+        "Vec<f16>" => return TypeId::FLOAT16_ARRAY as u32,
+        "Vec<f32>" => return TypeId::FLOAT32_ARRAY as u32,
+        "Vec<f64>" => return TypeId::FLOAT64_ARRAY as u32,
+        _ => {}
+    }
+
+    // Check collection types
+    if ty.starts_with("Vec<")
+        || ty.starts_with("VecDeque<")
+        || ty.starts_with("LinkedList<")
+        || ty.starts_with("BinaryHeap<")
+    {
+        return TypeId::LIST as u32;
+    }
+
+    if ty.starts_with("HashSet<") || ty.starts_with("BTreeSet<") {
+        return TypeId::SET as u32;
     }
 
+    if ty.starts_with("HashMap<") || ty.starts_with("BTreeMap<") {
+        return TypeId::MAP as u32;
+    }
+
+    // Unknown type
+    TypeId::UNKNOWN as u32
+}
+
+fn get_primitive_type_size(type_id_num: u32) -> i32 {
+    let type_id = TypeId::try_from(type_id_num as i16).unwrap();
+    match type_id {
+        TypeId::BOOL => 1,
+        TypeId::INT8 => 1,
+        TypeId::INT16 => 2,
+        TypeId::INT32 => 4,
+        TypeId::VAR_INT32 => 4,
+        TypeId::INT64 => 8,
+        TypeId::VAR_INT64 => 8,
+        TypeId::FLOAT16 => 2,
+        TypeId::FLOAT32 => 4,
+        TypeId::FLOAT64 => 8,
+        _ => unreachable!(),
+    }
+}
+
+fn is_compress(type_id: u32) -> bool {
+    [
+        TypeId::INT32 as u32,
+        TypeId::INT64 as u32,
+        TypeId::VAR_INT32 as u32,
+        TypeId::VAR_INT64 as u32,
+    ]
+    .contains(&type_id)
+}
+
+fn is_internal_type_id(type_id: u32) -> bool {
+    [
+        TypeId::STRING as u32,
+        TypeId::LOCAL_DATE as u32,
+        TypeId::TIMESTAMP as u32,
+        TypeId::DURATION as u32,
+        TypeId::DECIMAL as u32,
+        TypeId::BINARY as u32,
+        TypeId::BOOL_ARRAY as u32,
+        TypeId::INT8_ARRAY as u32,
+        TypeId::INT16_ARRAY as u32,
+        TypeId::INT32_ARRAY as u32,
+        TypeId::INT64_ARRAY as u32,
+        TypeId::FLOAT16_ARRAY as u32,
+        TypeId::FLOAT32_ARRAY as u32,
+        TypeId::FLOAT64_ARRAY as u32,
+    ]
+    .contains(&type_id)
+}
+
+fn group_fields_by_type(fields: &[&Field]) -> FieldGroups {
     let mut primitive_fields = Vec::new();
     let mut nullable_primitive_fields = Vec::new();
     let mut internal_type_fields = Vec::new();
@@ -418,44 +557,22 @@ fn group_fields_by_type(fields: &[&Field]) -> FieldGroups {
         }
     }
 
-    fn get_other_internal_type_id(ty: &str) -> u32 {
-        match ty {
-            "String" => TypeId::STRING as u32,
-            "NaiveDate" => TypeId::LOCAL_DATE as u32,
-            "NaiveDateTime" => TypeId::TIMESTAMP as u32,
-            "Duration" => TypeId::DURATION as u32,
-            "Decimal" => TypeId::DECIMAL as u32,
-            "Vec<u8>" | "bytes" => TypeId::BINARY as u32,
-            "Vec<bool>" => TypeId::BOOL_ARRAY as u32,
-            "Vec<i8>" => TypeId::INT8_ARRAY as u32,
-            "Vec<i16>" => TypeId::INT16_ARRAY as u32,
-            "Vec<i32>" => TypeId::INT32_ARRAY as u32,
-            "Vec<i64>" => TypeId::INT64_ARRAY as u32,
-            "Vec<f16>" => TypeId::FLOAT16_ARRAY as u32,
-            "Vec<f32>" => TypeId::FLOAT32_ARRAY as u32,
-            "Vec<f64>" => TypeId::FLOAT64_ARRAY as u32,
-            _ => 0,
-        }
-    }
-
     let mut group_field = |ident: String, ty: &str| {
+        let type_id = get_type_id_by_name(ty);
+        // Categorize based on type_id
         if PRIMITIVE_TYPE_NAMES.contains(&ty) {
-            primitive_fields.push((ident, ty.to_string(), get_primitive_type_id(ty)));
-        } else if get_other_internal_type_id(ty) > 0 {
-            let internal_type_id = get_other_internal_type_id(ty);
-            internal_type_fields.push((ident, ty.to_string(), internal_type_id));
-        } else if ty.starts_with("Vec<")
-            || ty.starts_with("VecDeque<")
-            || ty.starts_with("LinkedList<")
-            || ty.starts_with("BinaryHeap<")
-        {
-            list_fields.push((ident, ty.to_string(), TypeId::LIST as u32));
-        } else if ty.starts_with("HashSet<") || ty.starts_with("BTreeSet<") {
-            set_fields.push((ident, ty.to_string(), TypeId::SET as u32));
-        } else if ty.starts_with("HashMap<") || ty.starts_with("BTreeMap<") {
-            map_fields.push((ident, ty.to_string(), TypeId::MAP as u32));
+            primitive_fields.push((ident, ty.to_string(), type_id));
+        } else if is_internal_type_id(type_id) {
+            internal_type_fields.push((ident, ty.to_string(), type_id));
+        } else if type_id == TypeId::LIST as u32 {
+            list_fields.push((ident, ty.to_string(), type_id));
+        } else if type_id == TypeId::SET as u32 {
+            set_fields.push((ident, ty.to_string(), type_id));
+        } else if type_id == TypeId::MAP as u32 {
+            map_fields.push((ident, ty.to_string(), type_id));
         } else {
-            other_fields.push((ident, ty.to_string(), TypeId::UNKNOWN as u32));
+            // User-defined type
+            other_fields.push((ident, ty.to_string(), type_id));
         }
     };
 
@@ -487,33 +604,6 @@ fn group_fields_by_type(fields: &[&Field]) -> FieldGroups {
         }
     }
 
-    fn get_primitive_type_size(type_id_num: u32) -> i32 {
-        let type_id = TypeId::try_from(type_id_num as i16).unwrap();
-        match type_id {
-            TypeId::BOOL => 1,
-            TypeId::INT8 => 1,
-            TypeId::INT16 => 2,
-            TypeId::INT32 => 4,
-            TypeId::VAR_INT32 => 4,
-            TypeId::INT64 => 8,
-            TypeId::VAR_INT64 => 8,
-            TypeId::FLOAT16 => 2,
-            TypeId::FLOAT32 => 4,
-            TypeId::FLOAT64 => 8,
-            _ => unreachable!(),
-        }
-    }
-
-    fn is_compress(type_id: u32) -> bool {
-        [
-            TypeId::INT32 as u32,
-            TypeId::INT64 as u32,
-            TypeId::VAR_INT32 as u32,
-            TypeId::VAR_INT64 as u32,
-        ]
-        .contains(&type_id)
-    }
-
     fn numeric_sorter(a: &(String, String, u32), b: &(String, String, u32)) -> std::cmp::Ordering {
         let compress_a = is_compress(a.2);
         let compress_b = is_compress(b.2);
@@ -592,3 +682,35 @@ pub(crate) fn skip_ref_flag(ty: &Type) -> bool {
     // !T::fory_is_option() && PRIMITIVE_TYPES.contains(&elem_type_id)
     PRIMITIVE_TYPE_NAMES.contains(&extract_type_name(ty).as_str())
 }
+
+/// Determine whether to skip writing type info for a struct field based on its type.
+///
+/// According to xlang_serialization_spec.md:
+/// - Primitive fields: skip type info
+/// - Nullable primitive fields (Option<primitive>): skip type info
+/// - Internal type fields (String, Date, arrays): skip type info
+/// - List/Set/Map fields: skip type info
+/// - Struct fields: WRITE type info
+/// - Ext fields: WRITE type info
+/// - Enum fields: skip type info (enum is morphic)
+///
+/// Returns true if type info should be skipped, false if it should be written.
+pub(crate) fn should_skip_type_info_for_field(ty: &Type) -> bool {
+    let type_id = get_type_id_by_type_ast(ty);
+    if [
+        TypeId::STRUCT as u32,
+        TypeId::COMPATIBLE_STRUCT as u32,
+        TypeId::NAMED_STRUCT as u32,
+        TypeId::NAMED_COMPATIBLE_STRUCT as u32,
+        TypeId::EXT as u32,
+        TypeId::NAMED_EXT as u32,
+        TypeId::UNKNOWN as u32,
+    ]
+    .contains(&type_id)
+    {
+        // Struct and Ext types need type info
+        return false;
+    }
+    // Primitive, nullable primitive, internal types, List/Set/Map skip type info
+    true
+}
diff --git a/rust/fory-derive/src/object/write.rs b/rust/fory-derive/src/object/write.rs
index 035562ecd..f242da28d 100644
--- a/rust/fory-derive/src/object/write.rs
+++ b/rust/fory-derive/src/object/write.rs
@@ -16,9 +16,11 @@
 // under the License.
 
 use super::util::{
-    classify_trait_object_field, create_wrapper_types_arc, create_wrapper_types_rc, skip_ref_flag,
-    StructField,
+    classify_trait_object_field, create_wrapper_types_arc, create_wrapper_types_rc,
+    get_struct_name, get_type_id_by_type_ast, is_debug_enabled, should_skip_type_info_for_field,
+    skip_ref_flag, StructField,
 };
+use fory_core::types::TypeId;
 use proc_macro2::TokenStream;
 use quote::quote;
 use syn::Field;
@@ -27,7 +29,7 @@ pub fn gen_reserved_space(fields: &[&Field]) -> TokenStream {
     let reserved_size_expr: Vec<_> = fields.iter().map(|field| {
         let ty = &field.ty;
         match classify_trait_object_field(ty) {
-            StructField::BoxDyn(_) => {
+            StructField::BoxDyn => {
                 quote! {
                     fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
@@ -36,52 +38,52 @@ pub fn gen_reserved_space(fields: &[&Field]) -> TokenStream {
                 let types = create_wrapper_types_rc(&trait_name);
                 let wrapper_ty = types.wrapper_ty;
                 quote! {
-                    <#wrapper_ty as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <#wrapper_ty as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
             StructField::ArcDyn(trait_name) => {
                 let types = create_wrapper_types_arc(&trait_name);
                 let wrapper_ty = types.wrapper_ty;
                 quote! {
-                    <#wrapper_ty as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <#wrapper_ty as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
             StructField::VecRc(trait_name) => {
                 let types = create_wrapper_types_rc(&trait_name);
                 let wrapper_ty = types.wrapper_ty;
                 quote! {
-                    <Vec<#wrapper_ty> as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <Vec<#wrapper_ty> as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
             StructField::VecArc(trait_name) => {
                 let types = create_wrapper_types_arc(&trait_name);
                 let wrapper_ty = types.wrapper_ty;
                 quote! {
-                    <Vec<#wrapper_ty> as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <Vec<#wrapper_ty> as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
             StructField::HashMapRc(key_ty, trait_name) => {
                 let types = create_wrapper_types_rc(&trait_name);
                 let wrapper_ty = types.wrapper_ty;
                 quote! {
-                    <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
             StructField::HashMapArc(key_ty, trait_name) => {
                 let types = create_wrapper_types_arc(&trait_name);
                 let wrapper_ty = types.wrapper_ty;
                 quote! {
-                    <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
             StructField::Forward => {
                 quote! {
-                    <#ty as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <#ty as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
             _ => {
                 quote! {
-                    <#ty as fory_core::serializer::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
+                    <#ty as fory_core::Serializer>::fory_reserved_space() + fory_core::types::SIZE_OF_REF_AND_TYPE
                 }
             }
         }
@@ -95,34 +97,17 @@ pub fn gen_reserved_space(fields: &[&Field]) -> TokenStream {
 
 pub fn gen_write_type_info() -> TokenStream {
     quote! {
-        fory_core::serializer::struct_::write_type_info::<Self>(context, is_field)
+        fory_core::serializer::struct_::write_type_info::<Self>(context)
     }
 }
 
 fn gen_write_field(field: &Field) -> TokenStream {
     let ty = &field.ty;
     let ident = &field.ident;
-    match classify_trait_object_field(ty) {
-        StructField::BoxDyn(_) => {
+    let base = match classify_trait_object_field(ty) {
+        StructField::BoxDyn => {
             quote! {
-                {
-                    let any_ref = self.#ident.as_any();
-                    let concrete_type_id = any_ref.type_id();
-                    let fory_type_id = context.get_type_resolver()
-                        .get_fory_type_id(concrete_type_id)
-                        .ok_or_else(|| fory_core::error::Error::TypeError("Type not registered for trait object field".into()))?;
-
-                    context.writer.write_i8(fory_core::types::RefFlag::NotNullValue as i8)?;
-                    context.writer.write_varuint32(fory_type_id);
-
-                    let harness = context
-                        .get_type_resolver()
-                        .get_harness(fory_type_id)
-                        .ok_or_else(|| fory_core::error::Error::TypeError("Harness not found for trait object field".into()))?;
-
-                    let serializer_fn = harness.get_write_fn();
-                    serializer_fn(any_ref, context, true)?;
-                }
+                <#ty as fory_core::Serializer>::fory_write(&self.#ident, context, true, true, false)?;
             }
         }
         StructField::RcDyn(trait_name) => {
@@ -130,10 +115,8 @@ fn gen_write_field(field: &Field) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                {
-                    let wrapper = #wrapper_ty::from(self.#ident.clone() as std::rc::Rc<dyn #trait_ident>);
-                    fory_core::serializer::Serializer::fory_write(&wrapper, context, true)?;
-                }
+                let wrapper = #wrapper_ty::from(self.#ident.clone() as std::rc::Rc<dyn #trait_ident>);
+                <#wrapper_ty as fory_core::Serializer>::fory_write(&wrapper, context, true, true, false)?;
             }
         }
         StructField::ArcDyn(trait_name) => {
@@ -141,10 +124,8 @@ fn gen_write_field(field: &Field) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                {
-                    let wrapper = #wrapper_ty::from(self.#ident.clone() as std::sync::Arc<dyn #trait_ident>);
-                    fory_core::serializer::Serializer::fory_write(&wrapper, context, true)?;
-                }
+                let wrapper = #wrapper_ty::from(self.#ident.clone() as std::sync::Arc<dyn #trait_ident>);
+                <#wrapper_ty as fory_core::Serializer>::fory_write(&wrapper, context, true, true, false)?;
             }
         }
         StructField::VecRc(trait_name) => {
@@ -152,12 +133,10 @@ fn gen_write_field(field: &Field) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                {
-                    let wrapper_vec: Vec<#wrapper_ty> = self.#ident.iter()
-                        .map(|item| #wrapper_ty::from(item.clone() as std::rc::Rc<dyn #trait_ident>))
-                        .collect();
-                    fory_core::serializer::Serializer::fory_write(&wrapper_vec, context, true)?;
-                }
+                let wrapper_vec: Vec<#wrapper_ty> = self.#ident.iter()
+                    .map(|item| #wrapper_ty::from(item.clone() as std::rc::Rc<dyn #trait_ident>))
+                    .collect();
+                <Vec<#wrapper_ty> as fory_core::Serializer>::fory_write(&wrapper_vec, context, true, false, true)?;
             }
         }
         StructField::VecArc(trait_name) => {
@@ -165,12 +144,10 @@ fn gen_write_field(field: &Field) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                {
-                    let wrapper_vec: Vec<#wrapper_ty> = self.#ident.iter()
-                        .map(|item| #wrapper_ty::from(item.clone() as std::sync::Arc<dyn #trait_ident>))
-                        .collect();
-                    fory_core::serializer::Serializer::fory_write(&wrapper_vec, context, true)?;
-                }
+                let wrapper_vec: Vec<#wrapper_ty> = self.#ident.iter()
+                    .map(|item| #wrapper_ty::from(item.clone() as std::sync::Arc<dyn #trait_ident>))
+                    .collect();
+                <Vec<#wrapper_ty> as fory_core::Serializer>::fory_write(&wrapper_vec, context, true, false, true)?;
             }
         }
         StructField::HashMapRc(key_ty, trait_name) => {
@@ -178,12 +155,10 @@ fn gen_write_field(field: &Field) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                {
-                    let wrapper_map: std::collections::HashMap<#key_ty, #wrapper_ty> = self.#ident.iter()
-                        .map(|(k, v)| (k.clone(), #wrapper_ty::from(v.clone() as std::rc::Rc<dyn #trait_ident>)))
-                        .collect();
-                    fory_core::serializer::Serializer::fory_write(&wrapper_map, context, true)?;
-                }
+                let wrapper_map: std::collections::HashMap<#key_ty, #wrapper_ty> = self.#ident.iter()
+                    .map(|(k, v)| (k.clone(), #wrapper_ty::from(v.clone() as std::rc::Rc<dyn #trait_ident>)))
+                    .collect();
+                <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_write(&wrapper_map, context, true, false, true)?;
             }
         }
         StructField::HashMapArc(key_ty, trait_name) => {
@@ -191,27 +166,79 @@ fn gen_write_field(field: &Field) -> TokenStream {
             let wrapper_ty = types.wrapper_ty;
             let trait_ident = types.trait_ident;
             quote! {
-                {
-                    let wrapper_map: std::collections::HashMap<#key_ty, #wrapper_ty> = self.#ident.iter()
-                        .map(|(k, v)| (k.clone(), #wrapper_ty::from(v.clone() as std::sync::Arc<dyn #trait_ident>)))
-                        .collect();
-                    fory_core::serializer::Serializer::fory_write(&wrapper_map, context, true)?;
-                }
+                let wrapper_map: std::collections::HashMap<#key_ty, #wrapper_ty> = self.#ident.iter()
+                    .map(|(k, v)| (k.clone(), #wrapper_ty::from(v.clone() as std::sync::Arc<dyn #trait_ident>)))
+                    .collect();
+                <std::collections::HashMap<#key_ty, #wrapper_ty> as fory_core::Serializer>::fory_write(&wrapper_map, context, true, false, true)?;
             }
         }
         StructField::Forward => {
             quote! {
-                {
-                    fory_core::serializer::Serializer::fory_write(&self.#ident, context, true)?;
-                }
+                <#ty as fory_core::Serializer>::fory_write(&self.#ident, context, true, true, false)?;
             }
         }
         _ => {
             let skip_ref_flag = skip_ref_flag(ty);
-            quote! {
-                fory_core::serializer::write_ref_info_data::<#ty>(&self.#ident, context, true, #skip_ref_flag, false)?;
+            let skip_type_info = should_skip_type_info_for_field(ty);
+            let type_id = get_type_id_by_type_ast(ty);
+            if type_id == TypeId::LIST as u32
+                || type_id == TypeId::SET as u32
+                || type_id == TypeId::MAP as u32
+            {
+                quote! {
+                    <#ty as fory_core::Serializer>::fory_write(&self.#ident, context, true, false, true)?;
+                }
+            } else {
+                // Known types (primitives, strings, collections) - skip type info at compile time
+                // For custom types that we can't determine at compile time (like enums),
+                // we need to check at runtime whether to skip type info
+                if skip_type_info {
+                    if skip_ref_flag {
+                        quote! {
+                            <#ty as fory_core::Serializer>::fory_write_data(&self.#ident, context)?;
+                        }
+                    } else {
+                        quote! {
+                            <#ty as fory_core::Serializer>::fory_write(&self.#ident, context, true, false, false)?;
+                        }
+                    }
+                } else if skip_ref_flag {
+                    quote! {
+                        let is_enum = <#ty as fory_core::Serializer>::fory_static_type_id() == fory_core::types::TypeId::ENUM;
+                        <#ty as fory_core::Serializer>::fory_write(&self.#ident, context, false, !is_enum, false)?;
+                    }
+                } else {
+                    quote! {
+                        let is_enum = <#ty as fory_core::Serializer>::fory_static_type_id() == fory_core::types::TypeId::ENUM;
+                        <#ty as fory_core::Serializer>::fory_write(&self.#ident, context, true, !is_enum, false)?;
+                    }
+                }
             }
         }
+    };
+
+    if is_debug_enabled() {
+        let struct_name = get_struct_name().expect("struct context not set");
+        let struct_name_lit = syn::LitStr::new(&struct_name, proc_macro2::Span::call_site());
+        let field_name = field.ident.as_ref().unwrap().to_string();
+        let field_name_lit = syn::LitStr::new(&field_name, proc_macro2::Span::call_site());
+        quote! {
+            fory_core::serializer::struct_::struct_before_write_field(
+                #struct_name_lit,
+                #field_name_lit,
+                (&self.#ident) as &dyn std::any::Any,
+                context,
+            );
+            #base
+            fory_core::serializer::struct_::struct_after_write_field(
+                #struct_name_lit,
+                #field_name_lit,
+                (&self.#ident) as &dyn std::any::Any,
+                context,
+            );
+        }
+    } else {
+        base
     }
 }
 
@@ -225,6 +252,6 @@ pub fn gen_write_data(fields: &[&Field]) -> TokenStream {
 
 pub fn gen_write() -> TokenStream {
     quote! {
-        fory_core::serializer::struct_::write::<Self>(self, context, is_field)
+        fory_core::serializer::struct_::write::<Self>(self, context, write_ref_info, write_type_info)
     }
 }
diff --git a/rust/fory/src/lib.rs b/rust/fory/src/lib.rs
index b8e6c538f..b5c6d0117 100644
--- a/rust/fory/src/lib.rs
+++ b/rust/fory/src/lib.rs
@@ -717,14 +717,14 @@
 //! }
 //!
 //! impl Serializer for CustomType {
-//!     fn fory_write_data(&self, context: &mut WriteContext, is_field: bool) -> Result<(), Error> {
+//!     fn fory_write_data(&self, context: &mut WriteContext) -> Result<(), Error> {
 //!         context.writer.write_i32(self.value);
 //!         context.writer.write_varuint32(self.name.len() as u32);
 //!         context.writer.write_utf8_string(&self.name);
 //!         Ok(())
 //!     }
 //!
-//!     fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
+//!     fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
 //!         let value = context.reader.read_i32()?;
 //!         let len = context.reader.read_varuint32()? as usize;
 //!         let name = context.reader.read_utf8_string(len)?;
diff --git a/rust/tests/tests/compatible/test_container.rs b/rust/tests/tests/compatible/test_container.rs
index 9fa1969a5..0fc43c5ca 100644
--- a/rust/tests/tests/compatible/test_container.rs
+++ b/rust/tests/tests/compatible/test_container.rs
@@ -23,6 +23,7 @@ use fory_core::resolver::context::{ReadContext, WriteContext};
 use fory_derive::ForyObject;
 
 #[derive(ForyObject, PartialEq, Eq, Hash, Debug)]
+#[fory_debug]
 struct Item {
     id: i32,
 }
diff --git a/rust/tests/tests/compatible/test_struct.rs b/rust/tests/tests/compatible/test_struct.rs
index 46ccf1972..105edb106 100644
--- a/rust/tests/tests/compatible/test_struct.rs
+++ b/rust/tests/tests/compatible/test_struct.rs
@@ -142,6 +142,7 @@ fn nonexistent_struct() {
 #[test]
 fn option() {
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Animal {
         f1: Option<String>,
         f2: Option<String>,
@@ -285,6 +286,7 @@ fn nullable_container() {
 #[test]
 fn inner_nullable() {
     #[derive(ForyObject, Debug)]
+    #[fory_debug]
     pub struct Item1 {
         f1: Vec<Option<String>>,
         f2: HashSet<Option<i8>>,
@@ -293,6 +295,7 @@ fn inner_nullable() {
     }
 
     #[derive(ForyObject, Debug)]
+    #[fory_debug]
     pub struct Item2 {
         f1: Vec<String>,
         f2: HashSet<i8>,
@@ -322,6 +325,7 @@ fn inner_nullable() {
 #[test]
 fn nullable_struct() {
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     pub struct Item {
         name: String,
         data: Vec<Option<String>>,
@@ -329,6 +333,7 @@ fn nullable_struct() {
     }
 
     #[derive(ForyObject, Debug)]
+    #[fory_debug]
     pub struct Person1 {
         f1: Item,
         f2: Option<Item>,
@@ -337,6 +342,7 @@ fn nullable_struct() {
     }
 
     #[derive(ForyObject, Debug)]
+    #[fory_debug]
     pub struct Person2 {
         f1: Option<Item>,
         f2: Item,
@@ -391,6 +397,7 @@ fn enum_without_payload() {
         Blue,
     }
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Person1 {
         f1: Color1,
         f2: Color1,
@@ -403,6 +410,7 @@ fn enum_without_payload() {
         last: i8,
     }
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Person2 {
         // same
         f1: Color1,
@@ -458,6 +466,7 @@ fn named_enum() {
         White,
     }
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Item1 {
         f1: Color,
         f2: Color,
@@ -472,6 +481,7 @@ fn named_enum() {
         last: i8,
     }
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Item2 {
         f1: Color,
         f2: Option<Color>,
diff --git a/rust/tests/tests/compatible/test_struct_enum.rs b/rust/tests/tests/compatible/test_struct_enum.rs
index ca25a0aba..0d5d92ba6 100644
--- a/rust/tests/tests/compatible/test_struct_enum.rs
+++ b/rust/tests/tests/compatible/test_struct_enum.rs
@@ -26,6 +26,7 @@ use fory_derive::ForyObject;
 use std::collections::{HashMap, HashSet};
 
 #[derive(ForyObject, Debug, PartialEq, Eq, Hash)]
+#[fory_debug]
 struct Item {
     id: i32,
 }
@@ -40,6 +41,7 @@ enum Color {
 }
 
 #[derive(ForyObject, Debug, PartialEq)]
+#[fory_debug]
 struct Person {
     // primitive
     f1: bool,
@@ -78,6 +80,7 @@ struct Person {
 }
 
 #[derive(ForyObject, Debug, PartialEq)]
+#[fory_debug]
 struct Empty {}
 
 #[test]
@@ -165,6 +168,7 @@ fn skip_basic() {
 #[test]
 fn nested() {
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Element {
         f1: Vec<Item>,
         f2: HashSet<Item>,
@@ -174,6 +178,7 @@ fn nested() {
         f6: HashMap<Color, Color>,
     }
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Nested {
         f1: Vec<Item>,
         f2: HashSet<Item>,
@@ -216,6 +221,7 @@ fn nested() {
 #[test]
 fn compatible_nullable() {
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Nonnull {
         f1: bool,
         f2: i8,
@@ -241,6 +247,7 @@ fn compatible_nullable() {
         f29: HashMap<String, i32>,
     }
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct Nullable {
         f1: Option<bool>,
         f2: Option<i8>,
@@ -322,6 +329,7 @@ fn compatible_nullable() {
 #[test]
 fn name_mismatch() {
     #[derive(ForyObject, Debug, PartialEq)]
+    #[fory_debug]
     struct MismatchPerson {
         f2: bool,
         f3: i8,
@@ -402,13 +410,12 @@ fn ext() {
         fn fory_write_data(
             &self,
             context: &mut WriteContext,
-            is_field: bool,
         ) -> Result<(), fory_core::error::Error> {
-            write_data(&self.id, context, is_field)
+            write_data(&self.id, context)
         }
-        fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
+        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
             Ok(Self {
-                id: read_data(context, is_field)?,
+                id: read_data(context)?,
             })
         }
 
@@ -457,13 +464,12 @@ fn skip_ext() {
         fn fory_write_data(
             &self,
             context: &mut WriteContext,
-            is_field: bool,
         ) -> Result<(), fory_core::error::Error> {
-            write_data(&self.id, context, is_field)
+            write_data(&self.id, context)
         }
-        fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
+        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
             Ok(Self {
-                id: read_data(context, is_field)?,
+                id: read_data(context)?,
             })
         }
 
@@ -527,13 +533,12 @@ fn compatible_ext() {
         fn fory_write_data(
             &self,
             context: &mut WriteContext,
-            is_field: bool,
         ) -> Result<(), fory_core::error::Error> {
-            write_data(&self.id, context, is_field)
+            write_data(&self.id, context)
         }
-        fn fory_read_data(context: &mut ReadContext, is_field: bool) -> Result<Self, Error> {
+        fn fory_read_data(context: &mut ReadContext) -> Result<Self, Error> {
             Ok(Self {
-                id: read_data(context, is_field)?,
+                id: read_data(context)?,
             })
         }
         fn fory_type_id_dyn(
diff --git a/rust/tests/tests/mod.rs b/rust/tests/tests/mod.rs
index bc8c4e4d7..5b26bc5f0 100644
--- a/rust/tests/tests/mod.rs
+++ b/rust/tests/tests/mod.rs
@@ -16,4 +16,6 @@
 // under the License.
 
 mod compatible;
+mod test_any;
+mod test_collection;
 mod test_max_dyn_depth;
diff --git a/rust/tests/tests/test_collection.rs b/rust/tests/tests/test_collection.rs
index 116b39707..e8b3c2f72 100644
--- a/rust/tests/tests/test_collection.rs
+++ b/rust/tests/tests/test_collection.rs
@@ -21,7 +21,8 @@ use std::collections::{BTreeSet, BinaryHeap, HashSet};
 
 #[test]
 fn test_btreeset_roundtrip() {
-    let fory: Fory = Fory::default();
+    let mut fory: Fory = Fory::default();
+    fory.register_generic_trait::<BTreeSet<i32>>().unwrap();
 
     let mut original = BTreeSet::new();
     original.insert(1);
diff --git a/rust/tests/tests/test_cross_language.rs b/rust/tests/tests/test_cross_language.rs
index f6bfdc408..ffd571abb 100644
--- a/rust/tests/tests/test_cross_language.rs
+++ b/rust/tests/tests/test_cross_language.rs
@@ -250,17 +250,14 @@ fn test_string_serializer() {
     ];
     for s in &test_strings {
         // make is_field=true to skip read/write type_id
-        assert_eq!(*s, String::fory_read_data(&mut context, true).unwrap());
-        assert_eq!(
-            *s,
-            String::fory_read_data(&mut context_compress, true).unwrap()
-        );
+        assert_eq!(*s, String::fory_read_data(&mut context).unwrap());
+        assert_eq!(*s, String::fory_read_data(&mut context_compress).unwrap());
     }
     let writer = Writer::default();
     let fory = Fory::default().compatible(true).xlang(true);
     let mut context = WriteContext::new_from_fory(writer, &fory);
     for s in &test_strings {
-        s.fory_write_data(&mut context, true).unwrap();
+        s.fory_write_data(&mut context).unwrap();
     }
     fs::write(&data_file_path, context.writer.dump()).unwrap();
... 608 lines suppressed ...


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@fory.apache.org
For additional commands, e-mail: commits-help@fory.apache.org