diff --git a/CHANGELOG.md b/CHANGELOG.md
index 343b3bfc..ecf2bbfc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,11 +9,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Changed
 
+- `Animation`, `Audio`, `Document`, `PassportFile`, `PhotoSize`, `Video`, `VideoNote` and `Voice` now contain `FileMeta` instead of its fields ([#253][pr253])
+  - Field access should still work via `Deref` impls
 - **You can now `.await` any `Request`!** ([#249][pr249])
   - `Request` now requires `Self: IntoFuture`
   - There is no need for `AutoSend` anymore
 - MSRV (Minimal Supported Rust Version) was bumped from `1.58.0` to `1.64.0`
 
+[pr253]: https://github.com/teloxide/teloxide-core/pull/253
+
 ### Removed
 
 - Methods for creating `InlineQuery` ([#246][pr244])
diff --git a/src/types/animation.rs b/src/types/animation.rs
index 1d33d5ff..beb032db 100644
--- a/src/types/animation.rs
+++ b/src/types/animation.rs
@@ -1,22 +1,20 @@
+use derive_more::Deref;
 use mime::Mime;
 use serde::{Deserialize, Serialize};
 
-use crate::types::PhotoSize;
+use crate::types::{FileMeta, PhotoSize};
 
 /// This object represents an animation file (GIF or H.264/MPEG-4 AVC video
 /// without sound).
 ///
 /// [The official docs](https://core.telegram.org/bots/api#animation).
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct Animation {
-    /// An identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
+    /// Metadata of the animation file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// A video width as defined by a sender.
     pub width: u32,
@@ -36,14 +34,12 @@ pub struct Animation {
     /// A MIME type of the file as defined by a sender.
     #[serde(with = "crate::types::non_telegram_types::mime::opt_deser")]
     pub mime_type: Option<Mime>,
-
-    /// File size in bytes.
-    #[serde(default = "crate::types::file::file_size_fallback")]
-    pub file_size: u32,
 }
 
 #[cfg(test)]
 mod tests {
+    use crate::types::FileMeta;
+
     use super::*;
 
     #[test]
@@ -65,21 +61,25 @@ mod tests {
         "mime_type":"video/gif",
         "file_size":6500}"#;
         let expected = Animation {
-            file_id: "id".to_string(),
-            file_unique_id: "".to_string(),
+            file: FileMeta {
+                file_id: "id".to_string(),
+                file_unique_id: "".to_string(),
+                file_size: 6500,
+            },
             width: 320,
             height: 320,
             duration: 59,
             thumb: Some(PhotoSize {
-                file_id: "id".to_string(),
-                file_unique_id: "".to_string(),
+                file: FileMeta {
+                    file_id: "id".to_owned(),
+                    file_unique_id: "".to_owned(),
+                    file_size: 3452,
+                },
                 width: 320,
                 height: 320,
-                file_size: 3452,
             }),
             file_name: Some("some".to_string()),
             mime_type: Some("video/gif".parse().unwrap()),
-            file_size: 6500,
         };
         let actual = serde_json::from_str::<Animation>(json).unwrap();
         assert_eq!(actual, expected)
diff --git a/src/types/audio.rs b/src/types/audio.rs
index cfbfa888..1f17690a 100644
--- a/src/types/audio.rs
+++ b/src/types/audio.rs
@@ -1,22 +1,20 @@
+use derive_more::Deref;
 use mime::Mime;
 use serde::{Deserialize, Serialize};
 
-use crate::types::PhotoSize;
+use crate::types::{FileMeta, PhotoSize};
 
 /// This object represents an audio file to be treated as music by the Telegram
 /// clients.
 ///
 /// [The official docs](https://core.telegram.org/bots/api#audio).
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct Audio {
-    /// An identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
+    /// Metadata of the audio file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// A duration of the audio in seconds as defined by a sender.
     pub duration: u32,
@@ -34,16 +32,14 @@ pub struct Audio {
     #[serde(with = "crate::types::non_telegram_types::mime::opt_deser")]
     pub mime_type: Option<Mime>,
 
-    /// File size in bytes.
-    #[serde(default = "crate::types::file::file_size_fallback")]
-    pub file_size: u32,
-
     /// A thumbnail of the album cover to which the music file belongs.
     pub thumb: Option<PhotoSize>,
 }
 
 #[cfg(test)]
 mod tests {
+    use crate::types::FileMeta;
+
     use super::*;
 
     #[test]
@@ -65,19 +61,23 @@ mod tests {
             }
         }"#;
         let expected = Audio {
-            file_id: "id".to_string(),
-            file_unique_id: "".to_string(),
+            file: FileMeta {
+                file_id: "id".to_string(),
+                file_unique_id: "".to_string(),
+                file_size: 123_456,
+            },
             duration: 60,
             performer: Some("Performer".to_string()),
             title: Some("Title".to_string()),
             mime_type: Some("application/zip".parse().unwrap()),
-            file_size: 123_456,
             thumb: Some(PhotoSize {
-                file_id: "id".to_string(),
-                file_unique_id: "".to_string(),
+                file: FileMeta {
+                    file_id: "id".to_owned(),
+                    file_unique_id: "".to_owned(),
+                    file_size: 3452,
+                },
                 width: 320,
                 height: 320,
-                file_size: 3452,
             }),
             file_name: None,
         };
diff --git a/src/types/document.rs b/src/types/document.rs
index d391dee4..035cdd41 100644
--- a/src/types/document.rs
+++ b/src/types/document.rs
@@ -1,7 +1,8 @@
+use derive_more::Deref;
 use mime::Mime;
 use serde::{Deserialize, Serialize};
 
-use crate::types::PhotoSize;
+use crate::types::{FileMeta, PhotoSize};
 
 /// This object represents a general file (as opposed to [photos], [voice
 /// messages] and [audio files]).
@@ -12,15 +13,12 @@ use crate::types::PhotoSize;
 /// [voice messages]: https://core.telegram.org/bots/api#voice
 /// [audio files]: https://core.telegram.org/bots/api#audio
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct Document {
-    /// An identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
+    /// Metadata of the document file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// A document thumbnail as defined by a sender.
     pub thumb: Option<PhotoSize>,
@@ -31,8 +29,4 @@ pub struct Document {
     /// A MIME type of the file as defined by a sender.
     #[serde(default, with = "crate::types::non_telegram_types::mime::opt_deser")]
     pub mime_type: Option<Mime>,
-
-    /// File size in bytes.
-    #[serde(default = "crate::types::file::file_size_fallback")]
-    pub file_size: u32,
 }
diff --git a/src/types/passport_file.rs b/src/types/passport_file.rs
index 68a62972..935b3567 100644
--- a/src/types/passport_file.rs
+++ b/src/types/passport_file.rs
@@ -1,24 +1,21 @@
 use chrono::{DateTime, Utc};
+use derive_more::Deref;
 use serde::{Deserialize, Serialize};
 
+use crate::types::FileMeta;
+
 /// This object represents a file uploaded to Telegram Passport.
 ///
 /// Currently all Telegram Passport files are in JPEG format when decrypted and
 /// don't exceed 10MB.
 ///
 /// [The official docs](https://core.telegram.org/bots/api#passportfile).
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct PassportFile {
-    /// Identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
-
-    /// File size in bytes.
-    pub file_size: u32,
+    /// Metadata of the passport file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// Time when the file was uploaded.
     #[serde(with = "crate::types::serde_date_from_unix_timestamp")]
diff --git a/src/types/photo_size.rs b/src/types/photo_size.rs
index 6efc0e0d..5e030bd1 100644
--- a/src/types/photo_size.rs
+++ b/src/types/photo_size.rs
@@ -1,29 +1,25 @@
+use derive_more::Deref;
 use serde::{Deserialize, Serialize};
 
+use crate::types::FileMeta;
+
 /// This object represents one size of a photo or a [file]/[sticker] thumbnail.
 ///
 /// [file]: crate::types::Document
 /// [sticker]: crate::types::Sticker
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct PhotoSize {
-    /// Identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
+    /// Metadata of the photo file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// Photo width.
     pub width: u32,
 
     /// Photo height.
     pub height: u32,
-
-    /// File size in bytes.
-    #[serde(default = "crate::types::file::file_size_fallback")]
-    pub file_size: u32,
 }
 
 #[cfg(test)]
@@ -35,11 +31,13 @@ mod tests {
         let json = r#"{"file_id":"id","file_unique_id":"","width":320,"height":320,
                              "file_size":3452}"#;
         let expected = PhotoSize {
-            file_id: "id".to_string(),
-            file_unique_id: "".to_string(),
+            file: FileMeta {
+                file_id: "id".to_owned(),
+                file_unique_id: "".to_owned(),
+                file_size: 3452,
+            },
             width: 320,
             height: 320,
-            file_size: 3452,
         };
         let actual = serde_json::from_str::<PhotoSize>(json).unwrap();
         assert_eq!(actual, expected);
diff --git a/src/types/video.rs b/src/types/video.rs
index 3cb11ab1..e4bc736b 100644
--- a/src/types/video.rs
+++ b/src/types/video.rs
@@ -1,21 +1,19 @@
+use derive_more::Deref;
 use mime::Mime;
 use serde::{Deserialize, Serialize};
 
-use crate::types::PhotoSize;
+use crate::types::{FileMeta, PhotoSize};
 
 /// This object represents a video file.
 ///
 /// [The official docs](https://core.telegram.org/bots/api#video).
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct Video {
-    /// Identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
+    /// Metadata of the video file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// Video width as defined by sender.
     pub width: u32,
@@ -35,8 +33,4 @@ pub struct Video {
     /// Mime type of a file as defined by sender.
     #[serde(with = "crate::types::non_telegram_types::mime::opt_deser")]
     pub mime_type: Option<Mime>,
-
-    /// File size in bytes.
-    #[serde(default = "crate::types::file::file_size_fallback")]
-    pub file_size: u32,
 }
diff --git a/src/types/video_note.rs b/src/types/video_note.rs
index 980f15c9..9b82c643 100644
--- a/src/types/video_note.rs
+++ b/src/types/video_note.rs
@@ -1,6 +1,7 @@
+use derive_more::Deref;
 use serde::{Deserialize, Serialize};
 
-use crate::types::PhotoSize;
+use crate::types::{FileMeta, PhotoSize};
 
 /// This object represents a [video message] (available in Telegram apps as of
 /// [v.4.0]).
@@ -10,15 +11,12 @@ use crate::types::PhotoSize;
 /// [video message]: https://telegram.org/blog/video-messages-and-telescope
 /// [v4.0]: https://telegram.org/blog/video-messages-and-telescope
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct VideoNote {
-    /// Identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
+    /// Metadata of the video note file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// Video width and height (diameter of the video message) as defined by
     /// sender.
@@ -29,8 +27,4 @@ pub struct VideoNote {
 
     /// Video thumbnail.
     pub thumb: Option<PhotoSize>,
-
-    /// File size in bytes.
-    #[serde(default = "crate::types::file::file_size_fallback")]
-    pub file_size: u32,
 }
diff --git a/src/types/voice.rs b/src/types/voice.rs
index e44cfc7c..f124e08d 100644
--- a/src/types/voice.rs
+++ b/src/types/voice.rs
@@ -1,19 +1,19 @@
+use derive_more::Deref;
 use mime::Mime;
 use serde::{Deserialize, Serialize};
 
+use crate::types::FileMeta;
+
 /// This object represents a voice note.
 ///
 /// [The official docs](https://core.telegram.org/bots/api#voice).
 #[serde_with_macros::skip_serializing_none]
-#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
+#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize, Deref)]
 pub struct Voice {
-    /// Identifier for this file.
-    pub file_id: String,
-
-    /// Unique identifier for this file, which is supposed to be the same over
-    /// time and for different bots. Can't be used to download or reuse the
-    /// file.
-    pub file_unique_id: String,
+    /// Metadata of the voice file.
+    #[deref]
+    #[serde(flatten)]
+    pub file: FileMeta,
 
     /// Duration of the audio in seconds as defined by sender.
     pub duration: u32,
@@ -21,8 +21,4 @@ pub struct Voice {
     /// MIME type of the file as defined by sender.
     #[serde(with = "crate::types::non_telegram_types::mime::opt_deser")]
     pub mime_type: Option<Mime>,
-
-    /// File size in bytes.
-    #[serde(default = "crate::types::file::file_size_fallback")]
-    pub file_size: u32,
 }