diff --git a/substrate/primitives/src/sp_borsh.rs b/substrate/primitives/src/sp_borsh.rs
index 9e601f65..b474c6ab 100644
--- a/substrate/primitives/src/sp_borsh.rs
+++ b/substrate/primitives/src/sp_borsh.rs
@@ -17,21 +17,45 @@ pub fn borsh_deserialize_bitvec<R: Read>(
   Ok(bitvec::vec::BitVec::from_vec(bitvec))
 }
 
-type SerializeBoundedVecAs<T> = alloc::vec::Vec<T>;
-
-// TODO: Don't serialize this as a Vec<u8>. Shorten the length-prefix, technically encoding as an
-// enum.
 pub fn borsh_serialize_bounded_vec<W: Write, T: BorshSerialize, const B: u32>(
   bounded: &BoundedVec<T, ConstU32<B>>,
   writer: &mut W,
 ) -> Result<()> {
-  let vec: &SerializeBoundedVecAs<T> = bounded.as_ref();
-  BorshSerialize::serialize(vec, writer)
+  // Won't panic as `bytes_for_length` is <= 4
+  let bytes_for_length =
+    usize::try_from((u32::BITS - B.leading_zeros()).div_ceil(u8::BITS)).unwrap();
+  // Won't panic as this vec is bounded to a length specified as a u32
+  let length = u32::try_from(bounded.len()).unwrap().to_le_bytes();
+  writer.write_all(&length[0 .. bytes_for_length])?;
+
+  for item in bounded.as_slice() {
+    BorshSerialize::serialize(item, writer)?;
+  }
+
+  Ok(())
 }
 
 pub fn borsh_deserialize_bounded_vec<R: Read, T: BorshDeserialize, const B: u32>(
   reader: &mut R,
 ) -> Result<BoundedVec<T, ConstU32<B>>> {
-  let vec: SerializeBoundedVecAs<T> = BorshDeserialize::deserialize_reader(reader)?;
-  vec.try_into().map_err(|_| Error::new(ErrorKind::Other, "bound exceeded"))
+  // Won't panic as `bytes_for_length` is <= 4
+  let bytes_for_length =
+    usize::try_from((u32::BITS - B.leading_zeros()).div_ceil(u8::BITS)).unwrap();
+  let mut length = [0u8; 4];
+  reader.read_exact(&mut length[.. bytes_for_length])?;
+  let length = u32::from_le_bytes(length);
+  if length > B {
+    Err(Error::new(ErrorKind::Other, "bound exceeded"))?;
+  }
+
+  // Won't panic so long as usize >= u32
+  const {
+    assert!(usize::BITS >= u32::BITS, "wasn't compiled for at least a 32-bit platform");
+  }
+  let mut vec = alloc::vec::Vec::with_capacity(length.try_into().unwrap());
+  for _ in 0 .. length {
+    vec.push(T::deserialize_reader(reader)?);
+  }
+  // Won't panic as we already checked against the bound
+  Ok(vec.try_into().map_err(|_| ()).unwrap())
 }